1 В избранное 0 Ответвления 0

OSCHINA-MIRROR/devfeel-dotweb

Присоединиться к Gitlife
Откройте для себя и примите участие в публичных проектах с открытым исходным кодом с участием более 10 миллионов разработчиков. Приватные репозитории также полностью бесплатны :)
Присоединиться бесплатно
Клонировать/Скачать
server.go 19 КБ
Копировать Редактировать Web IDE Исходные данные Просмотреть построчно История
panxinming Отправлено 06.11.2019 19:16 8602371
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550
package dotweb
import (
"compress/gzip"
"io"
"net/http"
"net/url"
"strings"
"sync"
"github.com/devfeel/dotweb/logger"
"github.com/devfeel/dotweb/core"
"github.com/devfeel/dotweb/session"
"strconv"
"github.com/devfeel/dotweb/config"
"github.com/devfeel/dotweb/framework/file"
jsonutil "github.com/devfeel/dotweb/framework/json"
)
const (
DefaultGzipLevel = 9
gzipScheme = "gzip"
DefaultIndexPage = "index.html"
)
type (
HttpServer struct {
stdServer *http.Server
router Router
groups []Group
Modules []*HttpModule
DotApp *DotWeb
Validator Validator
sessionManager *session.SessionManager
lock_session *sync.RWMutex
pool *pool
binder Binder
render Renderer
offline bool
}
pool struct {
request sync.Pool
response sync.Pool
context sync.Pool
}
)
func NewHttpServer() *HttpServer {
server := &HttpServer{
pool: &pool{
response: sync.Pool{
New: func() interface{} {
return &Response{}
},
},
request: sync.Pool{
New: func() interface{} {
return &Request{}
},
},
context: sync.Pool{
New: func() interface{} {
return &HttpContext{}
},
},
},
Modules: make([]*HttpModule, 0),
lock_session: new(sync.RWMutex),
binder: newBinder(),
}
// setup router
server.router = NewRouter(server)
server.stdServer = &http.Server{Handler: server}
return server
}
// initConfig init config from app config
func (server *HttpServer) initConfig() {
}
// ServerConfig a shortcut for App.Config.ServerConfig
func (server *HttpServer) ServerConfig() *config.ServerNode {
return server.DotApp.Config.Server
}
// SessionConfig a shortcut for App.Config.SessionConfig
func (server *HttpServer) SessionConfig() *config.SessionNode {
return server.DotApp.Config.Session
}
// SetBinder set custom Binder on HttpServer
func (server *HttpServer) SetBinder(binder Binder) {
server.binder = binder
}
// ListenAndServe listens on the TCP network address srv.Addr and then
// calls Serve to handle requests on incoming connections.
func (server *HttpServer) ListenAndServe(addr string) error {
server.stdServer.Addr = addr
server.DotApp.Logger().Debug("DotWeb:HttpServer ListenAndServe ["+addr+"]", LogTarget_HttpServer)
return server.stdServer.ListenAndServe()
}
// ListenAndServeTLS listens on the TCP network address srv.Addr and
// then calls Serve to handle requests on incoming TLS connections.
// Accepted connections are configured to enable TCP keep-alives.
//
// Filenames containing a certificate and matching private key for the
// server must be provided if neither the Server's TLSConfig.Certificates
// nor TLSConfig.GetCertificate are populated. If the certificate is
// signed by a certificate authority, the certFile should be the
// concatenation of the server's certificate, any intermediates, and
// the CA's certificate.
//
// If srv.Addr is blank, ":https" is used.
//
// ListenAndServeTLS always returns a non-nil error.
func (server *HttpServer) ListenAndServeTLS(addr string, certFile, keyFile string) error {
server.stdServer.Addr = addr
// check tls config
if !file.Exist(certFile) {
server.DotApp.Logger().Error("DotWeb:HttpServer ListenAndServeTLS ["+addr+","+certFile+","+keyFile+"] error => Server EnabledTLS is true, but TLSCertFile not exists", LogTarget_HttpServer)
panic("Server EnabledTLS is true, but TLSCertFile not exists")
}
if !file.Exist(keyFile) {
server.DotApp.Logger().Error("DotWeb:HttpServer ListenAndServeTLS ["+addr+","+certFile+","+keyFile+"] error => Server EnabledTLS is true, but TLSKeyFile not exists", LogTarget_HttpServer)
panic("Server EnabledTLS is true, but TLSKeyFile not exists")
}
server.DotApp.Logger().Debug("DotWeb:HttpServer ListenAndServeTLS ["+addr+","+certFile+","+keyFile+"]", LogTarget_HttpServer)
return server.stdServer.ListenAndServeTLS(certFile, keyFile)
}
// ServeHTTP make sure request can be handled correctly
func (server *HttpServer) ServeHTTP(w http.ResponseWriter, req *http.Request) {
server.StateInfo().AddCurrentRequest(1)
defer server.StateInfo().SubCurrentRequest(1)
// special handling for websocket and debugging
if checkIsWebSocketRequest(req) {
http.DefaultServeMux.ServeHTTP(w, req)
server.StateInfo().AddRequestCount(req.URL.Path, defaultHttpCode, 1)
} else {
// setup header
w.Header().Set(HeaderServer, DefaultServerName)
httpCtx := prepareHttpContext(server, w, req)
// process OnBeginRequest of modules
for _, module := range server.Modules {
if module.OnBeginRequest != nil {
module.OnBeginRequest(httpCtx)
}
}
if !httpCtx.IsEnd() {
server.Router().ServeHTTP(httpCtx)
}
// process OnEndRequest of modules
for _, module := range server.Modules {
if module.OnEndRequest != nil {
module.OnEndRequest(httpCtx)
}
}
server.StateInfo().AddRequestCount(httpCtx.Request().Path(), httpCtx.Response().HttpCode(), 1)
releaseHttpContext(server, httpCtx)
}
}
// IsOffline check server is set offline state
func (server *HttpServer) IsOffline() bool {
return server.offline
}
// SetVirtualPath set current server's VirtualPath
func (server *HttpServer) SetVirtualPath(path string) {
server.ServerConfig().VirtualPath = path
server.DotApp.Logger().Debug("DotWeb:HttpServer SetVirtualPath ["+path+"]", LogTarget_HttpServer)
}
// VirtualPath return current server's VirtualPath
func (server *HttpServer) VirtualPath() string {
return server.ServerConfig().VirtualPath
}
// SetOffline set server offline config
func (server *HttpServer) SetOffline(offline bool, offlineText string, offlineUrl string) {
server.offline = offline
server.DotApp.Logger().Debug("DotWeb:HttpServer SetOffline ["+strconv.FormatBool(offline)+", "+offlineText+", "+offlineUrl+"]", LogTarget_HttpServer)
}
// IndexPage default index page name
func (server *HttpServer) IndexPage() string {
if server.ServerConfig().IndexPage == "" {
return DefaultIndexPage
} else {
return server.ServerConfig().IndexPage
}
}
// SetIndexPage set default index page name
func (server *HttpServer) SetIndexPage(indexPage string) {
server.ServerConfig().IndexPage = indexPage
server.DotApp.Logger().Debug("DotWeb:HttpServer SetIndexPage ["+indexPage+"]", LogTarget_HttpServer)
}
// SetSessionConfig set session store config
func (server *HttpServer) SetSessionConfig(storeConfig *session.StoreConfig) {
// sync session config
server.SessionConfig().Timeout = storeConfig.Maxlifetime
server.SessionConfig().SessionMode = storeConfig.StoreName
server.SessionConfig().ServerIP = storeConfig.ServerIP
server.SessionConfig().BackupServerUrl = storeConfig.BackupServerUrl
server.SessionConfig().StoreKeyPre = storeConfig.StoreKeyPre
server.SessionConfig().CookieName = storeConfig.CookieName
server.DotApp.Logger().Debug("DotWeb:HttpServer SetSessionConfig ["+jsonutil.GetJsonString(storeConfig)+"]", LogTarget_HttpServer)
}
// InitSessionManager init session manager
func (server *HttpServer) InitSessionManager() {
storeConfig := new(session.StoreConfig)
storeConfig.Maxlifetime = server.SessionConfig().Timeout
storeConfig.StoreName = server.SessionConfig().SessionMode
storeConfig.ServerIP = server.SessionConfig().ServerIP
storeConfig.BackupServerUrl = server.SessionConfig().BackupServerUrl
storeConfig.StoreKeyPre = server.SessionConfig().StoreKeyPre
storeConfig.CookieName = server.SessionConfig().CookieName
if server.sessionManager == nil {
// setup session
server.lock_session.Lock()
if manager, err := session.NewDefaultSessionManager(server.Logger(), storeConfig); err != nil {
// panic error with create session manager
panic(err.Error())
} else {
server.sessionManager = manager
}
server.lock_session.Unlock()
}
server.Logger().Debug("DotWeb:HttpServer InitSessionManager ["+jsonutil.GetJsonString(storeConfig)+"]", LogTarget_HttpServer)
}
// setDotApp associates the dotApp to the current HttpServer
func (server *HttpServer) setDotApp(dotApp *DotWeb) {
server.DotApp = dotApp
}
// GetSessionManager get session manager in current httpserver
func (server *HttpServer) GetSessionManager() *session.SessionManager {
if !server.SessionConfig().EnabledSession {
return nil
}
return server.sessionManager
}
// Logger is a shortcut for dotweb.Logger
func (server *HttpServer) Logger() logger.AppLog {
return server.DotApp.Logger()
}
// StateInfo is a shortcut for dotweb.StateInfo
func (server *HttpServer) StateInfo() *core.ServerStateInfo {
return server.DotApp.serverStateInfo
}
// Router get router interface in server
func (server *HttpServer) Router() Router {
return server.router
}
// GET is a shortcut for router.Handle("GET", path, handle)
func (server *HttpServer) GET(path string, handle HttpHandle) RouterNode {
return server.Router().GET(path, handle)
}
// ANY is a shortcut for router.Handle("Any", path, handle)
// it support GET\HEAD\POST\PUT\PATCH\OPTIONS\DELETE
func (server *HttpServer) Any(path string, handle HttpHandle) {
server.Router().Any(path, handle)
}
// HEAD is a shortcut for router.Handle("HEAD", path, handle)
func (server *HttpServer) HEAD(path string, handle HttpHandle) RouterNode {
return server.Router().HEAD(path, handle)
}
// OPTIONS is a shortcut for router.Handle("OPTIONS", path, handle)
func (server *HttpServer) OPTIONS(path string, handle HttpHandle) RouterNode {
return server.Router().OPTIONS(path, handle)
}
// POST is a shortcut for router.Handle("POST", path, handle)
func (server *HttpServer) POST(path string, handle HttpHandle) RouterNode {
return server.Router().POST(path, handle)
}
// PUT is a shortcut for router.Handle("PUT", path, handle)
func (server *HttpServer) PUT(path string, handle HttpHandle) RouterNode {
return server.Router().PUT(path, handle)
}
// PATCH is a shortcut for router.Handle("PATCH", path, handle)
func (server *HttpServer) PATCH(path string, handle HttpHandle) RouterNode {
return server.Router().PATCH(path, handle)
}
// DELETE is a shortcut for router.Handle("DELETE", path, handle)
func (server *HttpServer) DELETE(path string, handle HttpHandle) RouterNode {
return server.Router().DELETE(path, handle)
}
// ServerFile a shortcut for router.ServeFiles(path, fileRoot)
// simple demo:server.ServerFile("/src/*filepath", "/var/www")
func (server *HttpServer) ServerFile(path string, fileRoot string) RouterNode {
return server.Router().ServerFile(path, fileRoot)
}
// RegisterHandlerFunc a shortcut for router.RegisterHandlerFunc(routeMethod string, path string, handler http.HandlerFunc)
func (server *HttpServer) RegisterHandlerFunc(routeMethod string, path string, handler http.HandlerFunc) RouterNode {
return server.Router().RegisterHandlerFunc(routeMethod, path, handler)
}
// RegisterRoute a shortcut for router.RegisterRoute(routeMethod string, path string,handle HttpHandle)
func (server *HttpServer) RegisterRoute(routeMethod string, path string, handle HttpHandle) RouterNode {
return server.Router().RegisterRoute(routeMethod, path, handle)
}
// RegisterServerFile a shortcut for router.RegisterServerFile(routeMethod, path, fileRoot)
// simple demo:server.RegisterServerFile(RouteMethod_GET, "/src/*", "/var/www", nil)
// simple demo:server.RegisterServerFile(RouteMethod_GET, "/src/*filepath", "/var/www", []string{".zip", ".rar"})
func (server *HttpServer) RegisterServerFile(routeMethod string, path string, fileRoot string, excludeExtension []string) RouterNode {
return server.Router().RegisterServerFile(routeMethod, path, fileRoot, excludeExtension)
}
// HiJack is a shortcut for router.HiJack(path, handle)
func (server *HttpServer) HiJack(path string, handle HttpHandle) {
server.Router().HiJack(path, handle)
}
// WebSocket is a shortcut for router.WebSocket(path, handle)
func (server *HttpServer) WebSocket(path string, handle HttpHandle) {
server.Router().WebSocket(path, handle)
}
// Group create new group with current HttpServer
func (server *HttpServer) Group(prefix string) Group {
return NewGroup(prefix, server)
}
// Binder get binder interface in server
func (server *HttpServer) Binder() Binder {
return server.binder
}
// Renderer get renderer interface in server
// if no set, init InnerRenderer
func (server *HttpServer) Renderer() Renderer {
if server.render == nil {
if server.DotApp.RunMode() == RunMode_Development {
server.SetRenderer(NewInnerRendererNoCache())
} else {
server.SetRenderer(NewInnerRenderer())
}
}
return server.render
}
// SetRenderer set custom renderer in server
func (server *HttpServer) SetRenderer(r Renderer) {
server.render = r
server.Logger().Debug("DotWeb:HttpServer SetRenderer", LogTarget_HttpServer)
}
// SetEnabledAutoHEAD set route use auto head
// set EnabledAutoHEAD true or false
// default is false
func (server *HttpServer) SetEnabledAutoHEAD(isEnabled bool) {
server.ServerConfig().EnabledAutoHEAD = isEnabled
server.Logger().Debug("DotWeb:HttpServer SetEnabledAutoHEAD ["+strconv.FormatBool(isEnabled)+"]", LogTarget_HttpServer)
}
// SetEnabledAutoOPTIONS set route use auto options
// set SetEnabledAutoOPTIONS true or false
// default is false
func (server *HttpServer) SetEnabledAutoOPTIONS(isEnabled bool) {
server.ServerConfig().EnabledAutoOPTIONS = isEnabled
server.Logger().Debug("DotWeb:HttpServer SetEnabledAutoOPTIONS ["+strconv.FormatBool(isEnabled)+"]", LogTarget_HttpServer)
}
// SetEnabledRequestID set create unique request id per request
// set EnabledRequestID true or false
// default is false
func (server *HttpServer) SetEnabledRequestID(isEnabled bool) {
server.ServerConfig().EnabledRequestID = isEnabled
server.Logger().Debug("DotWeb:HttpServer SetEnabledRequestID ["+strconv.FormatBool(isEnabled)+"]", LogTarget_HttpServer)
}
// SetEnabledListDir set whether to allow listing of directories, default is false
func (server *HttpServer) SetEnabledListDir(isEnabled bool) {
server.ServerConfig().EnabledListDir = isEnabled
server.DotApp.Logger().Debug("DotWeb:HttpServer SetEnabledListDir ["+strconv.FormatBool(isEnabled)+"]", LogTarget_HttpServer)
}
// SetEnabledSession set whether to enable session, default is false
func (server *HttpServer) SetEnabledSession(isEnabled bool) {
server.SessionConfig().EnabledSession = isEnabled
server.Logger().Debug("DotWeb:HttpServer SetEnabledSession ["+strconv.FormatBool(isEnabled)+"]", LogTarget_HttpServer)
}
// SetEnabledGzip set whether to enable gzip, default is false
func (server *HttpServer) SetEnabledGzip(isEnabled bool) {
server.ServerConfig().EnabledGzip = isEnabled
server.Logger().Debug("DotWeb:HttpServer SetEnabledGzip ["+strconv.FormatBool(isEnabled)+"]", LogTarget_HttpServer)
}
// SetEnabledBindUseJsonTag set whethr to enable json tab on Bind, default is false
func (server *HttpServer) SetEnabledBindUseJsonTag(isEnabled bool) {
server.ServerConfig().EnabledBindUseJsonTag = isEnabled
server.Logger().Debug("DotWeb:HttpServer SetEnabledBindUseJsonTag ["+strconv.FormatBool(isEnabled)+"]", LogTarget_HttpServer)
}
// SetEnabledIgnoreFavicon set IgnoreFavicon Enabled
// default is false
func (server *HttpServer) SetEnabledIgnoreFavicon(isEnabled bool) {
server.ServerConfig().EnabledIgnoreFavicon = isEnabled
server.Logger().Debug("DotWeb:HttpServer SetEnabledIgnoreFavicon ["+strconv.FormatBool(isEnabled)+"]", LogTarget_HttpServer)
server.RegisterModule(getIgnoreFaviconModule())
}
// SetEnabledTLS set tls enabled
// default is false
// if it's true, must input certificate\private key fileName
func (server *HttpServer) SetEnabledTLS(isEnabled bool, certFile, keyFile string) {
server.ServerConfig().EnabledTLS = isEnabled
server.ServerConfig().TLSCertFile = certFile
server.ServerConfig().TLSKeyFile = keyFile
server.Logger().Debug("DotWeb:HttpServer SetEnabledTLS ["+strconv.FormatBool(isEnabled)+","+certFile+","+keyFile+"]", LogTarget_HttpServer)
}
// SetEnabledDetailRequestData 设置是否启用详细请求数据统计,默认为false
func (server *HttpServer) SetEnabledDetailRequestData(isEnabled bool) {
server.ServerConfig().EnabledDetailRequestData = isEnabled
server.Logger().Debug("DotWeb:HttpServer SetEnabledDetailRequestData ["+strconv.FormatBool(isEnabled)+"]", LogTarget_HttpServer)
}
// SetEnabledStaticFileMiddleware set flag which enabled or disabled middleware for static-file route
func (server *HttpServer) SetEnabledStaticFileMiddleware(isEnabled bool) {
server.ServerConfig().EnabledStaticFileMiddleware = isEnabled
server.Logger().Debug("DotWeb:HttpServer SetEnabledStaticFileMiddleware ["+strconv.FormatBool(isEnabled)+"]", LogTarget_HttpServer)
}
// SetMaxBodySize set body size to limit read
func (server *HttpServer) SetMaxBodySize(maxBodySize int64) {
server.ServerConfig().MaxBodySize = maxBodySize
server.Logger().Debug("DotWeb:HttpServer SetMaxBodySize ["+strconv.FormatInt(maxBodySize, 10)+"]", LogTarget_HttpServer)
}
// RegisterModule add HttpModule
func (server *HttpServer) RegisterModule(module *HttpModule) {
server.Modules = append(server.Modules, module)
server.Logger().Debug("DotWeb:HttpServer RegisterModule ["+module.Name+"]", LogTarget_HttpServer)
}
type LogJson struct {
RequestUrl string
HttpHeader string
HttpBody string
}
// check request is the websocket request
// check Connection contains upgrade
func checkIsWebSocketRequest(req *http.Request) bool {
if strings.Index(strings.ToLower(req.Header.Get("Connection")), "upgrade") >= 0 {
return true
}
return false
}
// check request is startwith /debug/
func checkIsDebugRequest(req *http.Request) bool {
if strings.Index(req.RequestURI, "/debug/") == 0 {
return true
}
return false
}
// prepareHttpContext init HttpContext, init session & gzip config on HttpContext
func prepareHttpContext(server *HttpServer, w http.ResponseWriter, req *http.Request) *HttpContext {
// get from pool
response := server.pool.response.Get().(*Response)
request := server.pool.request.Get().(*Request)
httpCtx := server.pool.context.Get().(*HttpContext)
httpCtx.reset(response, request, server, nil, nil, nil)
response.reset(w)
request.reset(req, httpCtx)
// session
// if exists client-sessionid, use it
// if not exists client-sessionid, new one
if httpCtx.HttpServer().SessionConfig().EnabledSession {
sessionId, err := httpCtx.HttpServer().GetSessionManager().GetClientSessionID(httpCtx.Request().Request)
if err == nil && sessionId != "" {
httpCtx.sessionID = sessionId
} else {
httpCtx.sessionID = httpCtx.HttpServer().GetSessionManager().NewSessionID()
cookie := &http.Cookie{
Name: httpCtx.HttpServer().sessionManager.StoreConfig().CookieName,
Value: url.QueryEscape(httpCtx.SessionID()),
Path: "/",
}
httpCtx.SetCookie(cookie)
}
}
// init gzip
if httpCtx.HttpServer().ServerConfig().EnabledGzip {
gw, err := gzip.NewWriterLevel(httpCtx.Response().Writer(), DefaultGzipLevel)
if err != nil {
panic("use gzip error -> " + err.Error())
}
grw := &gzipResponseWriter{Writer: gw, ResponseWriter: httpCtx.Response().Writer()}
httpCtx.Response().reset(grw)
httpCtx.Response().SetHeader(HeaderContentEncoding, gzipScheme)
}
return httpCtx
}
// releaseHttpContext release HttpContext, release gzip writer
func releaseHttpContext(server *HttpServer, httpCtx *HttpContext) {
// release response
httpCtx.Response().release()
server.pool.response.Put(httpCtx.Response())
// release request
httpCtx.Request().release()
server.pool.request.Put(httpCtx.Request())
// release context
httpCtx.release()
server.pool.context.Put(httpCtx)
if server.ServerConfig().EnabledGzip {
var w io.Writer
w = httpCtx.Response().Writer().(*gzipResponseWriter).Writer
w.(*gzip.Writer).Close()
}
}

Опубликовать ( 0 )

Вы можете оставить комментарий после Вход в систему

1
https://api.gitlife.ru/oschina-mirror/devfeel-dotweb.git
git@api.gitlife.ru:oschina-mirror/devfeel-dotweb.git
oschina-mirror
devfeel-dotweb
devfeel-dotweb
master