Commit bd61dd9f authored by astaxie's avatar astaxie

change a log about new version

parent 5b9ae544
package beego
import (
"fmt"
"github.com/astaxie/beego/context"
"net"
"net/http"
"net/http/fcgi"
"time"
)
type FilterFunc func(*context.Context)
type App struct {
Handlers *ControllerRegistor
}
// New returns a new PatternServeMux.
func NewApp() *App {
cr := NewControllerRegistor()
app := &App{Handlers: cr}
return app
}
func (app *App) Run() {
addr := HttpAddr
if HttpPort != 0 {
addr = fmt.Sprintf("%s:%d", HttpAddr, HttpPort)
}
var (
err error
l net.Listener
)
if UseFcgi {
if HttpPort == 0 {
l, err = net.Listen("unix", addr)
} else {
l, err = net.Listen("tcp", addr)
}
if err != nil {
BeeLogger.Fatal("Listen: ", err)
}
err = fcgi.Serve(l, app.Handlers)
} else {
if EnableHotUpdate {
server := &http.Server{
Handler: app.Handlers,
ReadTimeout: time.Duration(HttpServerTimeOut) * time.Second,
WriteTimeout: time.Duration(HttpServerTimeOut) * time.Second,
}
laddr, err := net.ResolveTCPAddr("tcp", addr)
if nil != err {
BeeLogger.Fatal("ResolveTCPAddr:", err)
}
l, err = GetInitListner(laddr)
theStoppable = newStoppable(l)
err = server.Serve(theStoppable)
theStoppable.wg.Wait()
CloseSelf()
} else {
s := &http.Server{
Addr: addr,
Handler: app.Handlers,
ReadTimeout: time.Duration(HttpServerTimeOut) * time.Second,
WriteTimeout: time.Duration(HttpServerTimeOut) * time.Second,
}
if HttpTLS {
err = s.ListenAndServeTLS(HttpCertFile, HttpKeyFile)
} else {
err = s.ListenAndServe()
}
}
}
if err != nil {
BeeLogger.Fatal("ListenAndServe: ", err)
}
}
func (app *App) Router(path string, c ControllerInterface, mappingMethods ...string) *App {
app.Handlers.Add(path, c, mappingMethods...)
return app
}
func (app *App) AutoRouter(c ControllerInterface) *App {
app.Handlers.AddAuto(c)
return app
}
func (app *App) Filter(pattern, action string, filter FilterFunc) *App {
app.Handlers.AddFilter(pattern, action, filter)
return app
}
func (app *App) SetViewsPath(path string) *App {
ViewsPath = path
return app
}
func (app *App) SetStaticPath(url string, path string) *App {
StaticDir[url] = path
return app
}
func (app *App) DelStaticPath(url string) *App {
delete(StaticDir, url)
return app
}
package beego
import (
"fmt"
"github.com/astaxie/beego/session"
"html/template"
"net"
"net/http"
"net/http/fcgi"
"os"
"path"
"runtime"
"time"
)
const VERSION = "0.9.0"
var (
BeeApp *App
AppName string
AppPath string
AppConfigPath string
StaticDir map[string]string
TemplateCache map[string]*template.Template
HttpAddr string
HttpPort int
RecoverPanic bool
AutoRender bool
PprofOn bool
ViewsPath string
RunMode string //"dev" or "prod"
AppConfig *Config
//related to session
GlobalSessions *session.Manager //GlobalSessions
SessionOn bool // whether auto start session,default is false
SessionProvider string // default session provider memory mysql redis
SessionName string // sessionName cookie's name
SessionGCMaxLifetime int64 // session's gc maxlifetime
SessionSavePath string // session savepath if use mysql/redis/file this set to the connectinfo
UseFcgi bool
MaxMemory int64
EnableGzip bool // enable gzip
DirectoryIndex bool //enable DirectoryIndex default is false
EnableHotUpdate bool //enable HotUpdate default is false
HttpServerTimeOut int64 //set httpserver timeout
ErrorsShow bool //set weather show errors
XSRFKEY string //set XSRF
EnableXSRF bool
XSRFExpire int
CopyRequestBody bool //When in raw application, You want to the reqeustbody
TemplateLeft string
TemplateRight string
)
func init() {
os.Chdir(path.Dir(os.Args[0]))
BeeApp = NewApp()
AppPath, _ = os.Getwd()
StaticDir = make(map[string]string)
TemplateCache = make(map[string]*template.Template)
HttpAddr = ""
HttpPort = 8080
AppName = "beego"
RunMode = "dev" //default runmod
AutoRender = true
RecoverPanic = true
PprofOn = false
ViewsPath = "views"
SessionOn = false
SessionProvider = "memory"
SessionName = "beegosessionID"
SessionGCMaxLifetime = 3600
SessionSavePath = ""
UseFcgi = false
MaxMemory = 1 << 26 //64MB
EnableGzip = false
StaticDir["/static"] = "static"
AppConfigPath = path.Join(AppPath, "conf", "app.conf")
HttpServerTimeOut = 0
ErrorsShow = true
XSRFKEY = "beegoxsrf"
XSRFExpire = 60
TemplateLeft = "{{"
TemplateRight = "}}"
ParseConfig()
runtime.GOMAXPROCS(runtime.NumCPU())
}
type App struct {
Handlers *ControllerRegistor
}
// New returns a new PatternServeMux.
func NewApp() *App {
cr := NewControllerRegistor()
app := &App{Handlers: cr}
return app
}
func (app *App) Run() {
addr := HttpAddr
if HttpPort != 0 {
addr = fmt.Sprintf("%s:%d", HttpAddr, HttpPort)
}
var (
err error
l net.Listener
)
if UseFcgi {
if HttpPort == 0 {
l, err = net.Listen("unix", addr)
} else {
l, err = net.Listen("tcp", addr)
}
if err != nil {
BeeLogger.Fatal("Listen: ", err)
}
err = fcgi.Serve(l, app.Handlers)
} else {
if EnableHotUpdate {
server := &http.Server{
Handler: app.Handlers,
ReadTimeout: time.Duration(HttpServerTimeOut) * time.Second,
WriteTimeout: time.Duration(HttpServerTimeOut) * time.Second,
}
laddr, err := net.ResolveTCPAddr("tcp", addr)
if nil != err {
BeeLogger.Fatal("ResolveTCPAddr:", err)
}
l, err = GetInitListner(laddr)
theStoppable = newStoppable(l)
err = server.Serve(theStoppable)
theStoppable.wg.Wait()
CloseSelf()
} else {
s := &http.Server{
Addr: addr,
Handler: app.Handlers,
ReadTimeout: time.Duration(HttpServerTimeOut) * time.Second,
WriteTimeout: time.Duration(HttpServerTimeOut) * time.Second,
}
err = s.ListenAndServe()
}
}
if err != nil {
BeeLogger.Fatal("ListenAndServe: ", err)
}
}
func (app *App) Router(path string, c ControllerInterface, mappingMethods ...string) *App {
app.Handlers.Add(path, c, mappingMethods...)
return app
}
func (app *App) AutoRouter(c ControllerInterface) *App {
app.Handlers.AddAuto(c)
return app
}
func (app *App) Filter(filter http.HandlerFunc) *App {
app.Handlers.Filter(filter)
return app
}
func (app *App) FilterParam(param string, filter http.HandlerFunc) *App {
app.Handlers.FilterParam(param, filter)
return app
}
func (app *App) FilterPrefixPath(path string, filter http.HandlerFunc) *App {
app.Handlers.FilterPrefixPath(path, filter)
return app
}
func (app *App) FilterAfter(filter http.HandlerFunc) *App {
app.Handlers.FilterAfter(filter)
return app
}
func (app *App) FilterParamAfter(param string, filter http.HandlerFunc) *App {
app.Handlers.FilterParamAfter(param, filter)
return app
}
func (app *App) FilterPrefixPathAfter(path string, filter http.HandlerFunc) *App {
app.Handlers.FilterPrefixPathAfter(path, filter)
return app
}
func (app *App) SetViewsPath(path string) *App {
ViewsPath = path
return app
}
func (app *App) SetStaticPath(url string, path string) *App {
StaticDir[url] = path
return app
}
func (app *App) DelStaticPath(url string) *App {
delete(StaticDir, url)
return app
}
func (app *App) ErrorLog(ctx *Context) {
BeeLogger.Printf("[ERR] host: '%s', request: '%s %s', proto: '%s', ua: '%s', remote: '%s'\n", ctx.Request.Host, ctx.Request.Method, ctx.Request.URL.Path, ctx.Request.Proto, ctx.Request.UserAgent(), ctx.Request.RemoteAddr)
}
func (app *App) AccessLog(ctx *Context) {
BeeLogger.Printf("[ACC] host: '%s', request: '%s %s', proto: '%s', ua: '%s', remote: '%s'\n", ctx.Request.Host, ctx.Request.Method, ctx.Request.URL.Path, ctx.Request.Proto, ctx.Request.UserAgent(), ctx.Request.RemoteAddr)
}
func RegisterController(path string, c ControllerInterface) *App {
BeeApp.Router(path, c)
return BeeApp
}
func Router(rootpath string, c ControllerInterface, mappingMethods ...string) *App {
BeeApp.Router(rootpath, c, mappingMethods...)
return BeeApp
......@@ -232,11 +24,6 @@ func AutoRouter(c ControllerInterface) *App {
return BeeApp
}
func RouterHandler(path string, c http.Handler) *App {
BeeApp.Handlers.AddHandler(path, c)
return BeeApp
}
func Errorhandler(err string, h http.HandlerFunc) *App {
ErrorMaps[err] = h
return BeeApp
......@@ -257,37 +44,18 @@ func DelStaticPath(url string) *App {
return BeeApp
}
func Filter(filter http.HandlerFunc) *App {
BeeApp.Filter(filter)
return BeeApp
}
func FilterParam(param string, filter http.HandlerFunc) *App {
BeeApp.FilterParam(param, filter)
return BeeApp
}
func FilterPrefixPath(path string, filter http.HandlerFunc) *App {
BeeApp.FilterPrefixPath(path, filter)
return BeeApp
}
func FilterAfter(filter http.HandlerFunc) *App {
BeeApp.FilterAfter(filter)
return BeeApp
}
func FilterParamAfter(param string, filter http.HandlerFunc) *App {
BeeApp.FilterParamAfter(param, filter)
return BeeApp
}
func FilterPrefixPathAfter(path string, filter http.HandlerFunc) *App {
BeeApp.FilterPrefixPathAfter(path, filter)
//action has four values:
//BeforRouter
//AfterStatic
//BeforExec
//AfterExec
func AddFilter(pattern, action string, filter FilterFunc) *App {
BeeApp.Filter(pattern, action, filter)
return BeeApp
}
func Run() {
//if AppConfigPath not In the conf/app.conf reParse config
if AppConfigPath != path.Join(AppPath, "conf", "app.conf") {
err := ParseConfig()
if err != nil {
......@@ -296,18 +64,18 @@ func Run() {
}
}
}
if PprofOn {
BeeApp.Router(`/debug/pprof`, &ProfController{})
BeeApp.Router(`/debug/pprof/:pp([\w]+)`, &ProfController{})
}
if SessionOn {
GlobalSessions, _ = session.NewManager(SessionProvider, SessionName, SessionGCMaxLifetime, SessionSavePath)
go GlobalSessions.GC()
}
err := BuildTemplate(ViewsPath)
if err != nil {
if RunMode == "dev" {
Warn(err)
if AutoRender {
err := BuildTemplate(ViewsPath)
if err != nil {
if RunMode == "dev" {
Warn(err)
}
}
}
registerErrorHander()
......
package beego
import (
"bufio"
"bytes"
"errors"
"io"
"github.com/astaxie/beego/config"
"github.com/astaxie/beego/session"
"html/template"
"os"
"path"
"runtime"
"strconv"
"strings"
"sync"
"unicode"
)
var (
bComment = []byte{'#'}
bEmpty = []byte{}
bEqual = []byte{'='}
bDQuote = []byte{'"'}
BeeApp *App
AppName string
AppPath string
AppConfigPath string
StaticDir map[string]string
TemplateCache map[string]*template.Template
HttpAddr string
HttpPort int
HttpTLS bool
HttpCertFile string
HttpKeyFile string
RecoverPanic bool
AutoRender bool
PprofOn bool
ViewsPath string
RunMode string //"dev" or "prod"
AppConfig config.ConfigContainer
//related to session
GlobalSessions *session.Manager //GlobalSessions
SessionOn bool // whether auto start session,default is false
SessionProvider string // default session provider memory mysql redis
SessionName string // sessionName cookie's name
SessionGCMaxLifetime int64 // session's gc maxlifetime
SessionSavePath string // session savepath if use mysql/redis/file this set to the connectinfo
UseFcgi bool
MaxMemory int64
EnableGzip bool // enable gzip
DirectoryIndex bool //enable DirectoryIndex default is false
EnableHotUpdate bool //enable HotUpdate default is false
HttpServerTimeOut int64 //set httpserver timeout
ErrorsShow bool //set weather show errors
XSRFKEY string //set XSRF
EnableXSRF bool
XSRFExpire int
CopyRequestBody bool //When in raw application, You want to the reqeustbody
TemplateLeft string
TemplateRight string
)
// A Config represents the configuration.
type Config struct {
filename string
comment map[int][]string // id: []{comment, key...}; id 1 is for main comment.
data map[string]string // key: value
offset map[string]int64 // key: offset; for editing.
sync.RWMutex
}
// ParseFile creates a new Config and parses the file configuration from the
// named file.
func LoadConfig(name string) (*Config, error) {
file, err := os.Open(name)
if err != nil {
return nil, err
}
cfg := &Config{
file.Name(),
make(map[int][]string),
make(map[string]string),
make(map[string]int64),
sync.RWMutex{},
}
cfg.Lock()
defer cfg.Unlock()
defer file.Close()
var comment bytes.Buffer
buf := bufio.NewReader(file)
for nComment, off := 0, int64(1); ; {
line, _, err := buf.ReadLine()
if err == io.EOF {
break
}
if bytes.Equal(line, bEmpty) {
continue
}
off += int64(len(line))
if bytes.HasPrefix(line, bComment) {
line = bytes.TrimLeft(line, "#")
line = bytes.TrimLeftFunc(line, unicode.IsSpace)
comment.Write(line)
comment.WriteByte('\n')
continue
}
if comment.Len() != 0 {
cfg.comment[nComment] = []string{comment.String()}
comment.Reset()
nComment++
}
val := bytes.SplitN(line, bEqual, 2)
if bytes.HasPrefix([]byte(strings.TrimSpace(string(val[1]))), bDQuote) {
val[1] = bytes.Trim([]byte(strings.TrimSpace(string(val[1]))), `"`)
}
key := strings.TrimSpace(string(val[0]))
cfg.comment[nComment-1] = append(cfg.comment[nComment-1], key)
cfg.data[key] = strings.TrimSpace(string(val[1]))
cfg.offset[key] = off
}
return cfg, nil
}
// Bool returns the boolean value for a given key.
func (c *Config) Bool(key string) (bool, error) {
return strconv.ParseBool(c.data[key])
}
// Int returns the integer value for a given key.
func (c *Config) Int(key string) (int, error) {
return strconv.Atoi(c.data[key])
}
func (c *Config) Int64(key string) (int64, error) {
return strconv.ParseInt(c.data[key], 10, 64)
}
// Float returns the float value for a given key.
func (c *Config) Float(key string) (float64, error) {
return strconv.ParseFloat(c.data[key], 64)
}
// String returns the string value for a given key.
func (c *Config) String(key string) string {
return c.data[key]
}
// WriteValue writes a new value for key.
func (c *Config) SetValue(key, value string) error {
c.Lock()
defer c.Unlock()
if _, found := c.data[key]; !found {
return errors.New("key not found: " + key)
}
c.data[key] = value
return nil
func init() {
os.Chdir(path.Dir(os.Args[0]))
BeeApp = NewApp()
AppPath, _ = os.Getwd()
StaticDir = make(map[string]string)
TemplateCache = make(map[string]*template.Template)
HttpAddr = ""
HttpPort = 8080
AppName = "beego"
RunMode = "dev" //default runmod
AutoRender = true
RecoverPanic = true
PprofOn = false
ViewsPath = "views"
SessionOn = false
SessionProvider = "memory"
SessionName = "beegosessionID"
SessionGCMaxLifetime = 3600
SessionSavePath = ""
UseFcgi = false
MaxMemory = 1 << 26 //64MB
EnableGzip = false
StaticDir["/static"] = "static"
AppConfigPath = path.Join(AppPath, "conf", "app.conf")
HttpServerTimeOut = 0
ErrorsShow = true
XSRFKEY = "beegoxsrf"
XSRFExpire = 60
TemplateLeft = "{{"
TemplateRight = "}}"
ParseConfig()
runtime.GOMAXPROCS(runtime.NumCPU())
}
func ParseConfig() (err error) {
AppConfig, err = LoadConfig(AppConfigPath)
AppConfig, err := config.NewConfig("ini", AppConfigPath)
if err != nil {
return err
} else {
......@@ -204,6 +164,15 @@ func ParseConfig() (err error) {
if tplright := AppConfig.String("templateright"); tplright != "" {
TemplateRight = tplright
}
if httptls, err := AppConfig.Bool("HttpTLS"); err == nil {
HttpTLS = httptls
}
if certfile := AppConfig.String("HttpCertFile"); certfile != "" {
HttpCertFile = certfile
}
if keyfile := AppConfig.String("HttpKeyFile"); keyfile != "" {
HttpKeyFile = keyfile
}
}
return nil
}
......@@ -16,6 +16,11 @@ func (ctx *Context) Redirect(status int, localurl string) {
ctx.Output.SetStatus(status)
}
func (ctx *Context) Abort(status int, body string) {
ctx.Output.SetStatus(status)
ctx.Output.Body([]byte(body))
}
func (ctx *Context) WriteString(content string) {
ctx.Output.Body([]byte(content))
}
......
......@@ -17,7 +17,7 @@ import (
)
type BeegoOutput struct {
context *Context
Context *Context
Status int
EnableGzip bool
res http.ResponseWriter
......@@ -35,8 +35,8 @@ func (output *BeegoOutput) Header(key, val string) {
func (output *BeegoOutput) Body(content []byte) {
output_writer := output.res.(io.Writer)
if output.EnableGzip == true && output.context.Input.Header("Accept-Encoding") != "" {
splitted := strings.SplitN(output.context.Input.Header("Accept-Encoding"), ",", -1)
if output.EnableGzip == true && output.Context.Input.Header("Accept-Encoding") != "" {
splitted := strings.SplitN(output.Context.Input.Header("Accept-Encoding"), ",", -1)
encodings := make([]string, len(splitted))
for i, val := range splitted {
......@@ -120,23 +120,40 @@ func sanitizeValue(v string) string {
return cookieValueSanitizer.Replace(v)
}
func (output *BeegoOutput) Json(data string) error {
func (output *BeegoOutput) Json(data interface{}, hasIndent bool, coding bool) error {
output.Header("Content-Type", "application/json;charset=UTF-8")
content, err := json.Marshal(data)
var content []byte
var err error
if hasIndent {
content, err = json.MarshalIndent(data, "", " ")
} else {
content, err = json.Marshal(data)
}
if err != nil {
http.Error(output.res, err.Error(), http.StatusInternalServerError)
return err
}
if coding {
content = []byte(stringsToJson(string(content)))
}
output.Body(content)
return nil
}
func (output *BeegoOutput) Jsonp(data string) error {
func (output *BeegoOutput) Jsonp(data interface{}, hasIndent bool) error {
output.Header("Content-Type", "application/javascript;charset=UTF-8")
content, err := json.Marshal(data)
var content []byte
var err error
if hasIndent {
content, err = json.MarshalIndent(data, "", " ")
} else {
content, err = json.Marshal(data)
}
if err != nil {
http.Error(output.res, err.Error(), http.StatusInternalServerError)
return err
}
callback := output.context.Input.Query("callback")
callback := output.Context.Input.Query("callback")
if callback == "" {
return errors.New(`"callback" parameter required`)
}
......@@ -148,10 +165,17 @@ func (output *BeegoOutput) Jsonp(data string) error {
return nil
}
func (output *BeegoOutput) Xml(data string) error {
func (output *BeegoOutput) Xml(data string, hasIndent bool) error {
output.Header("Content-Type", "application/xml;charset=UTF-8")
content, err := xml.Marshal(data)
var content []byte
var err error
if hasIndent {
content, err = xml.MarshalIndent(data, "", " ")
} else {
content, err = xml.Marshal(data)
}
if err != nil {
http.Error(output.res, err.Error(), http.StatusInternalServerError)
return err
}
output.Body(content)
......@@ -166,7 +190,7 @@ func (output *BeegoOutput) Download(file string) {
output.Header("Expires", "0")
output.Header("Cache-Control", "must-revalidate")
output.Header("Pragma", "public")
http.ServeFile(output.res, output.context.Request, file)
http.ServeFile(output.res, output.Context.Request, file)
}
func (output *BeegoOutput) ContentType(ext string) {
......@@ -219,3 +243,17 @@ func (output *BeegoOutput) IsClientError(status int) bool {
func (output *BeegoOutput) IsServerError(status int) bool {
return output.Status >= 500 && output.Status < 600
}
func stringsToJson(str string) string {
rs := []rune(str)
jsons := ""
for _, r := range rs {
rint := int(r)
if rint < 128 {
jsons += string(r)
} else {
jsons += "\\u" + strconv.FormatInt(int64(rint), 16) // json
}
}
return jsons
}
......@@ -2,15 +2,12 @@ package beego
import (
"bytes"
"compress/flate"
"compress/gzip"
"crypto/hmac"
"crypto/sha1"
"encoding/base64"
"encoding/json"
"encoding/xml"
"errors"
"fmt"
"github.com/astaxie/beego/context"
"github.com/astaxie/beego/session"
"html/template"
"io"
......@@ -26,7 +23,7 @@ import (
)
type Controller struct {
Ctx *Context
Ctx *context.Context
Data map[interface{}]interface{}
ChildName string
TplNames string
......@@ -39,7 +36,7 @@ type Controller struct {
}
type ControllerInterface interface {
Init(ct *Context, cn string)
Init(ct *Context, childName string)
Prepare()
Get()
Post()
......@@ -52,11 +49,11 @@ type ControllerInterface interface {
Render() error
}
func (c *Controller) Init(ctx *Context, cn string) {
func (c *Controller) Init(ctx *context.Context, childName string) {
c.Data = make(map[interface{}]interface{})
c.Layout = ""
c.TplNames = ""
c.ChildName = cn
c.ChildName = childName
c.Ctx = ctx
c.TplExt = "tpl"
}
......@@ -109,8 +106,8 @@ func (c *Controller) Render() error {
if err != nil {
return err
} else {
c.Ctx.ResponseWriter.Header().Set("Content-Type", "text/html; charset=utf-8")
c.writeToWriter(rb)
c.Ctx.Output.Header("Content-Type", "text/html; charset=utf-8")
c.Ctx.Output.Body(rb)
}
return nil
}
......@@ -172,41 +169,6 @@ func (c *Controller) RenderBytes() ([]byte, error) {
return []byte{}, nil
}
func (c *Controller) writeToWriter(rb []byte) {
output_writer := c.Ctx.ResponseWriter.(io.Writer)
if EnableGzip == true && c.Ctx.Request.Header.Get("Accept-Encoding") != "" {
splitted := strings.SplitN(c.Ctx.Request.Header.Get("Accept-Encoding"), ",", -1)
encodings := make([]string, len(splitted))
for i, val := range splitted {
encodings[i] = strings.TrimSpace(val)
}
for _, val := range encodings {
if val == "gzip" {
c.Ctx.ResponseWriter.Header().Set("Content-Encoding", "gzip")
output_writer, _ = gzip.NewWriterLevel(c.Ctx.ResponseWriter, gzip.BestSpeed)
break
} else if val == "deflate" {
c.Ctx.ResponseWriter.Header().Set("Content-Encoding", "deflate")
output_writer, _ = flate.NewWriter(c.Ctx.ResponseWriter, flate.BestSpeed)
break
}
}
} else {
c.Ctx.SetHeader("Content-Length", strconv.Itoa(len(rb)), true)
}
output_writer.Write(rb)
switch output_writer.(type) {
case *gzip.Writer:
output_writer.(*gzip.Writer).Close()
case *flate.Writer:
output_writer.(*flate.Writer).Close()
case io.WriteCloser:
output_writer.(io.WriteCloser).Close()
}
}
func (c *Controller) Redirect(url string, code int) {
c.Ctx.Redirect(code, url)
}
......@@ -216,63 +178,37 @@ func (c *Controller) Abort(code string) {
}
func (c *Controller) ServeJson(encoding ...bool) {
var content []byte
var err error
var hasIndent bool
var hasencoding bool
if RunMode == "prod" {
content, err = json.Marshal(c.Data["json"])
hasIndent = false
} else {
content, err = json.MarshalIndent(c.Data["json"], "", " ")
hasIndent = true
}
if err != nil {
http.Error(c.Ctx.ResponseWriter, err.Error(), http.StatusInternalServerError)
return
}
c.Ctx.ResponseWriter.Header().Set("Content-Type", "application/json;charset=UTF-8")
if len(encoding) > 0 && encoding[0] == true {
content = []byte(stringsToJson(string(content)))
hasencoding = true
}
c.writeToWriter(content)
c.Ctx.Output.Json(c.Data["json"], hasIndent, hasencoding)
}
func (c *Controller) ServeJsonp() {
var content []byte
var err error
var hasIndent bool
if RunMode == "prod" {
content, err = json.Marshal(c.Data["jsonp"])
hasIndent = false
} else {
content, err = json.MarshalIndent(c.Data["jsonp"], "", " ")
}
if err != nil {
http.Error(c.Ctx.ResponseWriter, err.Error(), http.StatusInternalServerError)
return
}
callback := c.Ctx.Request.Form.Get("callback")
if callback == "" {
http.Error(c.Ctx.ResponseWriter, `"callback" parameter required`, http.StatusInternalServerError)
return
hasIndent = true
}
callback_content := bytes.NewBufferString(callback)
callback_content.WriteString("(")
callback_content.Write(content)
callback_content.WriteString(");\r\n")
c.Ctx.ResponseWriter.Header().Set("Content-Type", "application/javascript;charset=UTF-8")
c.writeToWriter(callback_content.Bytes())
c.Ctx.Output.Jsonp(c.Data["jsonp"], hasIndent)
}
func (c *Controller) ServeXml() {
var content []byte
var err error
var hasIndent bool
if RunMode == "prod" {
content, err = xml.Marshal(c.Data["xml"])
hasIndent = false
} else {
content, err = xml.MarshalIndent(c.Data["xml"], "", " ")
hasIndent = true
}
if err != nil {
http.Error(c.Ctx.ResponseWriter, err.Error(), http.StatusInternalServerError)
return
}
c.Ctx.ResponseWriter.Header().Set("Content-Type", "application/xml;charset=UTF-8")
c.writeToWriter(content)
c.Ctx.Output.Xml(c.Data["xml"], hasIndent)
}
func (c *Controller) Input() url.Values {
......@@ -313,6 +249,10 @@ func (c *Controller) GetBool(key string) (bool, error) {
return strconv.ParseBool(c.Input().Get(key))
}
func (c *Controller) GetFloat(key string) (float64, error) {
return strconv.ParseFloat(c.Input().Get(key), 64)
}
func (c *Controller) GetFile(key string) (multipart.File, *multipart.FileHeader, error) {
return c.Ctx.Request.FormFile(key)
}
......@@ -365,7 +305,7 @@ func (c *Controller) DestroySession() {
}
func (c *Controller) IsAjax() bool {
return (c.Ctx.Request.Header.Get("HTTP_X_REQUESTED_WITH") == "XMLHttpRequest")
return c.Ctx.Input.IsAjax()
}
func (c *Controller) XsrfToken() string {
......
package beego
import (
"regexp"
)
type FilterRouter struct {
pattern string
regex *regexp.Regexp
filterFunc FilterFunc
hasregex bool
}
func (mr *FilterRouter) ValidRouter(router string) bool {
if mr.pattern == "" {
return true
}
if router == mr.pattern {
return true
}
if mr.hasregex {
if mr.regex.MatchString(router) {
return true
}
matches := mr.regex.FindStringSubmatch(router)
if len(matches[0]) == len(router) {
return true
}
}
return false
}
package middleware
import (
"fmt"
"html/template"
"net/http"
"runtime"
)
var tpl = `
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>beego application error</title>
<style>
html, body, body * {padding: 0; margin: 0;}
#header {background:#ffd; border-bottom:solid 2px #A31515; padding: 20px 10px;}
#header h2{ }
#footer {border-top:solid 1px #aaa; padding: 5px 10px; font-size: 12px; color:green;}
#content {padding: 5px;}
#content .stack b{ font-size: 13px; color: red;}
#content .stack pre{padding-left: 10px;}
table {}
td.t {text-align: right; padding-right: 5px; color: #888;}
</style>
<script type="text/javascript">
</script>
</head>
<body>
<div id="header">
<h2>{{.AppError}}</h2>
</div>
<div id="content">
<table>
<tr>
<td class="t">Request Method: </td><td>{{.RequestMethod}}</td>
</tr>
<tr>
<td class="t">Request URL: </td><td>{{.RequestURL}}</td>
</tr>
<tr>
<td class="t">RemoteAddr: </td><td>{{.RemoteAddr }}</td>
</tr>
</table>
<div class="stack">
<b>Stack</b>
<pre>{{.Stack}}</pre>
</div>
</div>
<div id="footer">
<p>beego {{ .BeegoVersion }} (beego framework)</p>
<p>golang version: {{.GoVersion}}</p>
</div>
</body>
</html>
`
func ShowErr(err interface{}, rw http.ResponseWriter, r *http.Request, Stack string) {
t, _ := template.New("beegoerrortemp").Parse(tpl)
data := make(map[string]string)
data["AppError"] = AppName + ":" + fmt.Sprint(err)
data["RequestMethod"] = r.Method
data["RequestURL"] = r.RequestURI
data["RemoteAddr"] = r.RemoteAddr
data["Stack"] = Stack
data["BeegoVersion"] = VERSION
data["GoVersion"] = runtime.Version()
t.Execute(rw, data)
}
var errtpl = `
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>{{.Title}}</title>
<style type="text/css">
* {
margin:0;
padding:0;
}
body {
background-color:#EFEFEF;
font: .9em "Lucida Sans Unicode", "Lucida Grande", sans-serif;
}
#wrapper{
width:600px;
margin:40px auto 0;
text-align:center;
-moz-box-shadow: 5px 5px 10px rgba(0,0,0,0.3);
-webkit-box-shadow: 5px 5px 10px rgba(0,0,0,0.3);
box-shadow: 5px 5px 10px rgba(0,0,0,0.3);
}
#wrapper h1{
color:#FFF;
text-align:center;
margin-bottom:20px;
}
#wrapper a{
display:block;
font-size:.9em;
padding-top:20px;
color:#FFF;
text-decoration:none;
text-align:center;
}
#container {
width:600px;
padding-bottom:15px;
background-color:#FFFFFF;
}
.navtop{
height:40px;
background-color:#24B2EB;
padding:13px;
}
.content {
padding:10px 10px 25px;
background: #FFFFFF;
margin:;
color:#333;
}
a.button{
color:white;
padding:15px 20px;
text-shadow:1px 1px 0 #00A5FF;
font-weight:bold;
text-align:center;
border:1px solid #24B2EB;
margin:0px 200px;
clear:both;
background-color: #24B2EB;
border-radius:100px;
-moz-border-radius:100px;
-webkit-border-radius:100px;
}
a.button:hover{
text-decoration:none;
background-color: #24B2EB;
}
</style>
</head>
<body>
<div id="wrapper">
<div id="container">
<div class="navtop">
<h1>{{.Title}}</h1>
</div>
<div id="content">
{{.Content}}
<a href="/" title="Home" class="button">Go Home</a><br />
<br>power by beego {{.BeegoVersion}}
</div>
</div>
</div>
</body>
</html>
`
var ErrorMaps map[string]http.HandlerFunc
func init() {
ErrorMaps = make(map[string]http.HandlerFunc)
}
//404
func NotFound(rw http.ResponseWriter, r *http.Request) {
t, _ := template.New("beegoerrortemp").Parse(errtpl)
data := make(map[string]interface{})
data["Title"] = "Page Not Found"
data["Content"] = template.HTML("<br>The Page You have requested flown the coop." +
"<br>Perhaps you are here because:" +
"<br><br><ul>" +
"<br>The page has moved" +
"<br>The page no longer exists" +
"<br>You were looking for your puppy and got lost" +
"<br>You like 404 pages" +
"</ul>")
data["BeegoVersion"] = VERSION
rw.WriteHeader(http.StatusNotFound)
t.Execute(rw, data)
}
//401
func Unauthorized(rw http.ResponseWriter, r *http.Request) {
t, _ := template.New("beegoerrortemp").Parse(errtpl)
data := make(map[string]interface{})
data["Title"] = "Unauthorized"
data["Content"] = template.HTML("<br>The Page You have requested can't authorized." +
"<br>Perhaps you are here because:" +
"<br><br><ul>" +
"<br>Check the credentials that you supplied" +
"<br>Check the address for errors" +
"</ul>")
data["BeegoVersion"] = VERSION
rw.WriteHeader(http.StatusUnauthorized)
t.Execute(rw, data)
}
//403
func Forbidden(rw http.ResponseWriter, r *http.Request) {
t, _ := template.New("beegoerrortemp").Parse(errtpl)
data := make(map[string]interface{})
data["Title"] = "Forbidden"
data["Content"] = template.HTML("<br>The Page You have requested forbidden." +
"<br>Perhaps you are here because:" +
"<br><br><ul>" +
"<br>Your address may be blocked" +
"<br>The site may be disabled" +
"<br>You need to log in" +
"</ul>")
data["BeegoVersion"] = VERSION
rw.WriteHeader(http.StatusForbidden)
t.Execute(rw, data)
}
//503
func ServiceUnavailable(rw http.ResponseWriter, r *http.Request) {
t, _ := template.New("beegoerrortemp").Parse(errtpl)
data := make(map[string]interface{})
data["Title"] = "Service Unavailable"
data["Content"] = template.HTML("<br>The Page You have requested unavailable." +
"<br>Perhaps you are here because:" +
"<br><br><ul>" +
"<br><br>The page is overloaded" +
"<br>Please try again later." +
"</ul>")
data["BeegoVersion"] = VERSION
rw.WriteHeader(http.StatusServiceUnavailable)
t.Execute(rw, data)
}
//500
func InternalServerError(rw http.ResponseWriter, r *http.Request) {
t, _ := template.New("beegoerrortemp").Parse(errtpl)
data := make(map[string]interface{})
data["Title"] = "Internal Server Error"
data["Content"] = template.HTML("<br>The Page You have requested has down now." +
"<br><br><ul>" +
"<br>simply try again later" +
"<br>you should report the fault to the website administrator" +
"</ul>")
data["BeegoVersion"] = VERSION
rw.WriteHeader(http.StatusInternalServerError)
t.Execute(rw, data)
}
func registerErrorHander() {
if _, ok := ErrorMaps["404"]; !ok {
ErrorMaps["404"] = NotFound
}
if _, ok := ErrorMaps["401"]; !ok {
ErrorMaps["401"] = Unauthorized
}
if _, ok := ErrorMaps["403"]; !ok {
ErrorMaps["403"] = Forbidden
}
if _, ok := ErrorMaps["503"]; !ok {
ErrorMaps["503"] = ServiceUnavailable
}
if _, ok := ErrorMaps["500"]; !ok {
ErrorMaps["500"] = InternalServerError
}
}
package middleware
\ No newline at end of file
package middleware
import (
"fmt"
"log"
"os"
"runtime"
"runtime/debug"
"runtime/pprof"
"strconv"
"sync/atomic"
"time"
)
var heapProfileCounter int32
var startTime = time.Now()
var pid int
func init() {
pid = os.Getpid()
}
func StartCPUProfile() {
f, err := os.Create("cpu-" + strconv.Itoa(pid) + ".pprof")
if err != nil {
log.Fatal(err)
}
pprof.StartCPUProfile(f)
}
func StopCPUProfile() {
pprof.StopCPUProfile()
}
func StartBlockProfile(rate int) {
runtime.SetBlockProfileRate(rate)
}
func StopBlockProfile() {
filename := "block-" + strconv.Itoa(pid) + ".pprof"
f, err := os.Create(filename)
if err != nil {
log.Fatal(err)
}
if err = pprof.Lookup("block").WriteTo(f, 0); err != nil {
log.Fatalf(" can't write %s: %s", filename, err)
}
f.Close()
}
func SetMemProfileRate(rate int) {
runtime.MemProfileRate = rate
}
func GC() {
runtime.GC()
}
func DumpHeap() {
filename := "heap-" + strconv.Itoa(pid) + "-" + strconv.Itoa(int(atomic.AddInt32(&heapProfileCounter, 1))) + ".pprof"
f, err := os.Create(filename)
if err != nil {
fmt.Fprintf(os.Stderr, "testing: %s", err)
return
}
if err = pprof.WriteHeapProfile(f); err != nil {
fmt.Fprintf(os.Stderr, "testing: can't write %s: %s", filename, err)
}
f.Close()
}
//func showSystemStat(interval time.Duration, count int) {
// usage1 := &syscall.Rusage{}
// var lastUtime int64
// var lastStime int64
// counter := 0
// for {
// //http://man7.org/linux/man-pages/man3/vtimes.3.html
// syscall.Getrusage(syscall.RUSAGE_SELF, usage1)
// utime := (usage1.Utime.Sec * 1000000000) + int64(usage1.Utime.Usec)
// stime := (usage1.Stime.Sec * 1000000000) + int64(usage1.Stime.Usec)
// userCPUUtil := float64(utime-lastUtime) * 100 / float64(interval)
// sysCPUUtil := float64(stime-lastStime) * 100 / float64(interval)
// memUtil := usage1.Maxrss * 1024
// lastUtime = utime
// lastStime = stime
// if counter > 0 {
// fmt.Printf("cpu: %3.2f%% us %3.2f%% sy, mem:%s \n", userCPUUtil, sysCPUUtil, toH(uint64(memUtil)))
// }
// counter += 1
// if count >= 1 && count < counter {
// return
// }
// time.Sleep(interval)
// }
//}
//func ShowSystemStat(seconds int) {
// go func() {
// interval := time.Duration(seconds) * time.Second
// showSystemStat(interval, 0)
// }()
//}
//func PrintSystemStats() {
// interval := time.Duration(1) * time.Second
// showSystemStat(interval, 1)
//}
func ShowGCStat() {
go func() {
var numGC int64
interval := time.Duration(100) * time.Millisecond
gcstats := &debug.GCStats{PauseQuantiles: make([]time.Duration, 100)}
memStats := &runtime.MemStats{}
for {
debug.ReadGCStats(gcstats)
if gcstats.NumGC > numGC {
runtime.ReadMemStats(memStats)
printGC(memStats, gcstats)
numGC = gcstats.NumGC
}
time.Sleep(interval)
}
}()
}
func PrintGCSummary() {
memStats := &runtime.MemStats{}
runtime.ReadMemStats(memStats)
gcstats := &debug.GCStats{PauseQuantiles: make([]time.Duration, 100)}
debug.ReadGCStats(gcstats)
printGC(memStats, gcstats)
}
func printGC(memStats *runtime.MemStats, gcstats *debug.GCStats) {
if gcstats.NumGC > 0 {
lastPause := gcstats.Pause[0]
elapsed := time.Now().Sub(startTime)
overhead := float64(gcstats.PauseTotal) / float64(elapsed) * 100
allocatedRate := float64(memStats.TotalAlloc) / elapsed.Seconds()
fmt.Printf("NumGC:%d Pause:%s Pause(Avg):%s Overhead:%3.2f%% Alloc:%s Sys:%s Alloc(Rate):%s/s Histogram:%s %s %s \n",
gcstats.NumGC,
toS(lastPause),
toS(avg(gcstats.Pause)),
overhead,
toH(memStats.Alloc),
toH(memStats.Sys),
toH(uint64(allocatedRate)),
toS(gcstats.PauseQuantiles[94]),
toS(gcstats.PauseQuantiles[98]),
toS(gcstats.PauseQuantiles[99]))
} else {
// while GC has disabled
elapsed := time.Now().Sub(startTime)
allocatedRate := float64(memStats.TotalAlloc) / elapsed.Seconds()
fmt.Printf("Alloc:%s Sys:%s Alloc(Rate):%s/s\n",
toH(memStats.Alloc),
toH(memStats.Sys),
toH(uint64(allocatedRate)))
}
}
func avg(items []time.Duration) time.Duration {
var sum time.Duration
for _, item := range items {
sum += item
}
return time.Duration(int64(sum) / int64(len(items)))
}
// human readable format
func toH(bytes uint64) string {
switch {
case bytes < 1024:
return fmt.Sprintf("%dB", bytes)
case bytes < 1024*1024:
return fmt.Sprintf("%.2fK", float64(bytes)/1024)
case bytes < 1024*1024*1024:
return fmt.Sprintf("%.2fM", float64(bytes)/1024/1024)
default:
return fmt.Sprintf("%.2fG", float64(bytes)/1024/1024/1024)
}
}
// short string format
func toS(d time.Duration) string {
u := uint64(d)
if u < uint64(time.Second) {
switch {
case u == 0:
return "0"
case u < uint64(time.Microsecond):
return fmt.Sprintf("%.2fns", float64(u))
case u < uint64(time.Millisecond):
return fmt.Sprintf("%.2fus", float64(u)/1000)
default:
return fmt.Sprintf("%.2fms", float64(u)/1000/1000)
}
} else {
switch {
case u < uint64(time.Minute):
return fmt.Sprintf("%.2fs", float64(u)/1000/1000/1000)
case u < uint64(time.Hour):
return fmt.Sprintf("%.2fm", float64(u)/1000/1000/1000/60)
default:
return fmt.Sprintf("%.2fh", float64(u)/1000/1000/1000/60/60)
}
}
}
package middleware
import (
"github.com/astaxie/beego/session"
)
var (
GlobalSessions *session.Manager
)
func StartSession(provideName, cookieName string, maxlifetime int64, savePath string) {
GlobalSessions, _ = session.NewManager(provideName, cookieName, maxlifetime, savePath)
go GlobalSessions.GC()
}
package beego
import (
"net/http/pprof"
)
type ProfController struct {
Controller
}
func (this *ProfController) Get() {
switch this.Ctx.Params[":pp"] {
default:
pprof.Index(this.Ctx.ResponseWriter, this.Ctx.Request)
case "":
pprof.Index(this.Ctx.ResponseWriter, this.Ctx.Request)
case "cmdline":
pprof.Cmdline(this.Ctx.ResponseWriter, this.Ctx.Request)
case "profile":
pprof.Profile(this.Ctx.ResponseWriter, this.Ctx.Request)
case "symbol":
pprof.Symbol(this.Ctx.ResponseWriter, this.Ctx.Request)
}
this.Ctx.ResponseWriter.WriteHeader(200)
}
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment