diff --git a/net/ghttp/ghttp_request_param.go b/net/ghttp/ghttp_request_param.go index 48a1f94a8..1140fc8d1 100644 --- a/net/ghttp/ghttp_request_param.go +++ b/net/ghttp/ghttp_request_param.go @@ -35,6 +35,10 @@ var ( // // The parameter can be type of: *struct/**struct/*[]struct/*[]*struct. // +// It supports single and multiple struct convertion: +// 1. Single struct, post content like: {"id":1, "name":"john"} +// 2. Multiple struct, post content like: [{"id":1, "name":"john"}, {"id":, "name":"smith"}] +// // TODO: Improve the performance by reducing duplicated reflect usage on the same variable across packages. func (r *Request) Parse(pointer interface{}) error { var ( @@ -52,15 +56,20 @@ func (r *Request) Parse(pointer interface{}) error { reflectKind2 = reflectVal2.Kind() ) switch reflectKind2 { + // Single struct, post content like: + // {"id":1, "name":"john"} case reflect.Ptr, reflect.Struct: - // Struct conversion. + // Conversion. if err := r.GetStruct(pointer); err != nil { return err } - // Struct validation. + // Validation. if err := gvalid.CheckStruct(pointer, nil); err != nil { return err } + + // Multiple struct, post content like: + // [{"id":1, "name":"john"}, {"id":, "name":"smith"}] case reflect.Array, reflect.Slice: // If struct slice conversion, it might post JSON/XML content, // so it uses gjson for the conversion. diff --git a/net/ghttp/ghttp_server_cookie.go b/net/ghttp/ghttp_server_cookie.go index eb5a1f95a..260252900 100644 --- a/net/ghttp/ghttp_server_cookie.go +++ b/net/ghttp/ghttp_server_cookie.go @@ -13,27 +13,29 @@ import ( "github.com/gogf/gf/os/gtime" ) -// COOKIE对象,非并发安全。 +// Cookie for HTTP COOKIE management. type Cookie struct { - data map[string]CookieItem // 数据项 - path string // 默认的cookie path - domain string // 默认的cookie domain - maxage time.Duration // 默认的cookie maxage - server *Server // 所属Server - request *Request // 所属HTTP请求对象 - response *Response // 所属HTTP返回对象 + data map[string]CookieItem // Underlying cookie items. + path string // The default cookie path. + domain string // The default cookie domain + maxage time.Duration // The default cookie maxage. + server *Server // Belonged HTTP server + request *Request // Belonged HTTP request. + response *Response // Belonged HTTP response. } -// cookie项 +// CookieItem is cookie item stored in Cookie management object. type CookieItem struct { - value string - domain string // 有效域名 - path string // 有效路径 - expireAt int64 // 过期时间 + value string // Cookie value. + domain string // Cookie domain. + path string // Cookie path. + expireAt int64 // Cookie expiration timestamp. httpOnly bool } -// 获取或者创建一个COOKIE对象,与传入的请求对应(延迟初始化) +// GetCookie creates or retrieves a cookie object with given request. +// It retrieves and returns an existing cookie object if it already exists with given request. +// It creates and returns a new cookie object if it does not exist with given request. func GetCookie(r *Request) *Cookie { if r.Cookie != nil { return r.Cookie @@ -44,7 +46,7 @@ func GetCookie(r *Request) *Cookie { } } -// 从请求流中初始化,无锁,延迟初始化 +// init does lazy initialization for cookie object. func (c *Cookie) init() { if c.data == nil { c.data = make(map[string]CookieItem) @@ -64,7 +66,7 @@ func (c *Cookie) init() { } } -// 获取所有的Cookie并构造成map[string]string返回. +// Map returns the cookie items as map[string]string. func (c *Cookie) Map() map[string]string { c.init() m := make(map[string]string) @@ -74,7 +76,7 @@ func (c *Cookie) Map() map[string]string { return m } -// 判断Cookie中是否存在制定键名(并且没有过期) +// Contains checks if given key exists and not expired in cookie. func (c *Cookie) Contains(key string) bool { c.init() if r, ok := c.data[key]; ok { @@ -85,12 +87,14 @@ func (c *Cookie) Contains(key string) bool { return false } -// 设置cookie,使用默认参数 +// Set sets cookie item with default domain, path and expiration age. func (c *Cookie) Set(key, value string) { c.SetCookie(key, value, c.domain, c.path, c.server.GetCookieMaxAge()) } -// 设置cookie,带详细cookie参数 +// SetCookie sets cookie item given given domain, path and expiration age. +// The optional parameter specifies if the cookie item is only available in HTTP, +// which is usually empty. func (c *Cookie) SetCookie(key, value, domain, path string, maxAge time.Duration, httpOnly ...bool) { c.init() isHttpOnly := false @@ -102,17 +106,18 @@ func (c *Cookie) SetCookie(key, value, domain, path string, maxAge time.Duration } } -// 获得客户端提交的SessionId +// GetSessionId retrieves and returns the session id from cookie. func (c *Cookie) GetSessionId() string { return c.Get(c.server.GetSessionIdName()) } -// 设置SessionId到Cookie中 +// SetSessionId sets session id in the cookie. func (c *Cookie) SetSessionId(id string) { c.Set(c.server.GetSessionIdName(), id) } -// 查询cookie +// Get retrieves and returns the value with specified key. +// It returns if specified key does not exist and is given. func (c *Cookie) Get(key string, def ...string) string { c.init() if r, ok := c.data[key]; ok { @@ -126,24 +131,26 @@ func (c *Cookie) Get(key string, def ...string) string { return "" } -// 删除COOKIE,使用默认的domain&path +// Remove deletes specified key and its value from cookie using default domain and path. +// It actually tells the http client that the cookie is expired, do not send it to server next time. func (c *Cookie) Remove(key string) { c.SetCookie(key, "", c.domain, c.path, -86400) } -// 标记该cookie在对应的域名和路径失效 -// 删除cookie的重点是需要通知浏览器客户端cookie已过期 +// RemoveCookie deletes specified key and its value from cookie using given domain and path. +// It actually tells the http client that the cookie is expired, do not send it to server next time. func (c *Cookie) RemoveCookie(key, domain, path string) { c.SetCookie(key, "", domain, path, -86400) } -// 输出到客户端 +// Output outputs the cookie items to client. func (c *Cookie) Output() { if len(c.data) == 0 { return } for k, v := range c.data { - // 只有 expire != 0 的才是服务端在本次请求中设置的cookie + // Cookie item matches expire != 0 means it is set in this request, + // which should be outputted to client. if v.expireAt == 0 { continue } diff --git a/net/ghttp/ghttp_server_domain.go b/net/ghttp/ghttp_server_domain.go index 25faf9ea0..a3018be8a 100644 --- a/net/ghttp/ghttp_server_domain.go +++ b/net/ghttp/ghttp_server_domain.go @@ -10,13 +10,13 @@ import ( "strings" ) -// 域名管理器对象 +// Domain is used for route register for domains. type Domain struct { - server *Server // 所属Server - domains map[string]struct{} // 多域名 + server *Server // Belonged server + domains map[string]struct{} // Support multiple domains. } -// 生成一个域名对象, 参数 domains 支持给定多个域名。 +// Domain creates and returns a domain object for management for one or more domains. func (s *Server) Domain(domains string) *Domain { d := &Domain{ server: s, diff --git a/net/ghttp/ghttp_server_graceful.go b/net/ghttp/ghttp_server_graceful.go index da48a4c11..9c19213f4 100644 --- a/net/ghttp/ghttp_server_graceful.go +++ b/net/ghttp/ghttp_server_graceful.go @@ -19,19 +19,20 @@ import ( "os" ) -// 优雅的Web Server对象封装 +// gracefulServer wraps the net/http.Server with graceful reload/restart feature. type gracefulServer struct { server *Server // Belonged server. - fd uintptr // 热重启时传递的socket监听文件句柄 - address string // 监听地址信息 - httpServer *http.Server // 底层http.Server - rawListener net.Listener // 原始listener - listener net.Listener // 接口化封装的listener - isHttps bool // 是否HTTPS - status int // 当前Server状态(关闭/运行) + fd uintptr // File descriptor for passing to child process when graceful reload. + address string // Listening address like:":80", ":8080". + httpServer *http.Server // Underlying http.Server. + rawListener net.Listener // Underlying net.Listener. + listener net.Listener // Wrapped net.Listener. + isHttps bool // Is HTTPS. + status int // Status of current server. } -// 创建一个优雅的Http Server +// newGracefulServer creates and returns a graceful http server with given address. +// The optional parameter specifies the file descriptor which is passed from parent server. func (s *Server) newGracefulServer(address string, fd ...int) *gracefulServer { // Change port to address like: 80 -> :80 if gstr.IsNumeric(address) { @@ -42,14 +43,13 @@ func (s *Server) newGracefulServer(address string, fd ...int) *gracefulServer { address: address, httpServer: s.newHttpServer(address), } - // 是否有继承的文件描述符 if len(fd) > 0 && fd[0] > 0 { gs.fd = uintptr(fd[0]) } return gs } -// 生成一个底层的Web Server对象 +// newGracefulServer creates and returns a underlying http.Server with given address. func (s *Server) newHttpServer(address string) *http.Server { server := &http.Server{ Addr: address, @@ -64,7 +64,7 @@ func (s *Server) newHttpServer(address string) *http.Server { return server } -// 执行HTTP监听 +// ListenAndServe starts listening on configured address. func (s *gracefulServer) ListenAndServe() error { ln, err := s.getNetListener() if err != nil { @@ -75,7 +75,8 @@ func (s *gracefulServer) ListenAndServe() error { return s.doServe() } -// 获得文件描述符 +// Fd retrieves and returns the file descriptor of current server. +// It is available ony in *nix like operation systems like: linux, unix, darwin. func (s *gracefulServer) Fd() uintptr { if s.rawListener != nil { file, err := s.rawListener.(*net.TCPListener).File() @@ -86,12 +87,14 @@ func (s *gracefulServer) Fd() uintptr { return 0 } -// 设置自定义fd +// setFd sets the file descriptor for current server. func (s *gracefulServer) setFd(fd int) { s.fd = uintptr(fd) } -// 执行HTTPS监听 +// ListenAndServeTLS starts listening on configured address with HTTPS. +// The parameter and specify the necessary certification and key files for HTTPS. +// The optional parameter specifies the custom TLS configuration. func (s *gracefulServer) ListenAndServeTLS(certFile, keyFile string, tlsConfig ...*tls.Config) error { var config *tls.Config if len(tlsConfig) > 0 && tlsConfig[0] != nil { @@ -122,7 +125,7 @@ func (s *gracefulServer) ListenAndServeTLS(certFile, keyFile string, tlsConfig . return s.doServe() } -// 获取服务协议字符串 +// getProto retrieves and returns the proto string of current server. func (s *gracefulServer) getProto() string { proto := "http" if s.isHttps { @@ -131,7 +134,7 @@ func (s *gracefulServer) getProto() string { return proto } -// 开始执行Web Server服务处理 +// doServe does staring the serving. func (s *gracefulServer) doServe() error { action := "started" if s.fd != 0 { @@ -147,7 +150,7 @@ func (s *gracefulServer) doServe() error { return err } -// 自定义的net.Listener +// getNetListener retrieves and returns the wrapped net.Listener. func (s *gracefulServer) getNetListener() (net.Listener, error) { var ln net.Listener var err error @@ -167,7 +170,7 @@ func (s *gracefulServer) getNetListener() (net.Listener, error) { return ln, err } -// 执行请求优雅关闭 +// shutdown shuts down the server gracefully. func (s *gracefulServer) shutdown() { if s.status == SERVER_STATUS_STOPPED { return @@ -180,7 +183,7 @@ func (s *gracefulServer) shutdown() { } } -// 执行请求强制关闭 +// close shuts down the server forcibly. func (s *gracefulServer) close() { if s.status == SERVER_STATUS_STOPPED { return diff --git a/net/ghttp/ghttp_server_handler.go b/net/ghttp/ghttp_server_handler.go index 362797e73..b03dabc65 100644 --- a/net/ghttp/ghttp_server_handler.go +++ b/net/ghttp/ghttp_server_handler.go @@ -24,38 +24,42 @@ import ( "github.com/gogf/gf/os/gtime" ) -// 默认HTTP Server处理入口,http包底层默认使用了gorutine异步处理请求,所以这里不再异步执行 +// ServeHTTP is the default handler for http request. +// It should not create new goroutine handling the request as +// it's called by am already created new goroutine from http.Server. +// +// This function also make serve implementing the interface of http.Handler. func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { // Max body size limit. if s.config.ClientMaxBodySize > 0 { r.Body = http.MaxBytesReader(w, r.Body, s.config.ClientMaxBodySize) } - // 重写规则判断 + + // Rewrite feature checks. if len(s.config.Rewrites) > 0 { if rewrite, ok := s.config.Rewrites[r.URL.Path]; ok { r.URL.Path = rewrite } } - // 去掉末尾的"/"号 + // Remove char '/' in the tail of URI. if r.URL.Path != "/" { for len(r.URL.Path) > 0 && r.URL.Path[len(r.URL.Path)-1] == '/' { r.URL.Path = r.URL.Path[:len(r.URL.Path)-1] } } - // URI默认值 + // Default URI value if it's empty. if r.URL.Path == "" { r.URL.Path = "/" } - // 创建请求处理对象 + // Create a new request object. request := newRequest(s, r, w) defer func() { - // 设置请求完成时间 request.LeaveTime = gtime.TimestampMilli() - // error log + // error log handling. if request.error != nil { s.handleErrorLog(request.error, request) } else { @@ -64,18 +68,20 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { s.handleErrorLog(gerror.Newf("%v", exception), request) } } - // access log + // access log handling. s.handleAccessLog(request) - // 关闭当前Session,并更新会话超时时间 + // Close the session, which automatically update the TTL + // of the session if it exists. request.Session.Close() }() // ============================================================ - // 优先级控制: - // 静态文件 > 动态服务 > 静态目录 + // Priority: + // Static File > Dynamic Service > Static Directory // ============================================================ - // 优先执行静态文件检索(检测是否存在对应的静态文件,包括index files处理) + // Search the static file with most high priority, + // which also handle the index files feature. if s.config.FileServerEnabled { request.StaticFile = s.searchStaticFile(r.URL.Path) if request.StaticFile != nil { @@ -83,29 +89,29 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { } } - // 动态服务检索 + // Search the dynamic service handler. request.handlers, request.hasHookHandler, request.hasServeHandler = s.getHandlersWithCache(request) - // 判断最终对该请求提供的服务方式 + // Check the service type static or dynamic for current request. if request.StaticFile != nil && request.StaticFile.IsDir && request.hasServeHandler { request.isFileRequest = false } - // 事件 - BeforeServe + // HOOK - BeforeServe s.callHookHandler(HOOK_BEFORE_SERVE, request) - // 执行静态文件服务/回调控制器/执行对象/方法 + // Core serving handling. if !request.IsExited() { if request.isFileRequest { - // 静态服务 + // Static file service. s.serveFile(request, request.StaticFile) } else { if len(request.handlers) > 0 { - // 动态服务 + // Dynamic service. request.Middleware.Next() } else { if request.StaticFile != nil && request.StaticFile.IsDir { - // 静态目录 + // Serve the directory. s.serveFile(request, request.StaticFile) } else { if len(request.Response.Header()) == 0 && @@ -118,12 +124,12 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { } } - // 事件 - AfterServe + // HOOK - AfterServe if !request.IsExited() { s.callHookHandler(HOOK_AFTER_SERVE, request) } - // 事件 - BeforeOutput + // HOOK - BeforeOutput if !request.IsExited() { s.callHookHandler(HOOK_BEFORE_OUTPUT, request) } @@ -146,15 +152,16 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { } } - // 设置Session Id到Cookie中 + // Automatically set the session id to cookie + // if it creates a new session id in this request. if request.Session.IsDirty() && request.Session.Id() != request.GetSessionId() { request.Cookie.SetSessionId(request.Session.Id()) } - // 输出Cookie + // Output the cookie content to client. request.Cookie.Output() - // 输出缓冲区 + // Output the buffer content to client. request.Response.Output() - // 事件 - AfterOutput + // HOOK - AfterOutput if !request.IsExited() { s.callHookHandler(HOOK_AFTER_OUTPUT, request) } @@ -222,9 +229,10 @@ func (s *Server) searchStaticFile(uri string) *StaticFile { return nil } -// http server静态文件处理,path可以为相对路径也可以为绝对路径 +// serveFile serves the static file for client. +// The optional parameter specifies if allowing directory listing if is directory. func (s *Server) serveFile(r *Request, f *StaticFile, allowIndex ...bool) { - // 使用资源文件 + // Use resource file from memory. if f.File != nil { if f.IsDir { if s.config.IndexFolder || (len(allowIndex) > 0 && allowIndex[0]) { @@ -239,7 +247,7 @@ func (s *Server) serveFile(r *Request, f *StaticFile, allowIndex ...bool) { } return } - // 使用磁盘文件 + // Use file from dist. file, err := os.Open(f.Path) if err != nil { r.Response.WriteStatus(http.StatusForbidden) @@ -264,7 +272,7 @@ func (s *Server) serveFile(r *Request, f *StaticFile, allowIndex ...bool) { } } -// 显示目录列表 +// listDir lists the sub files of specified directory as HTML content to client. func (s *Server) listDir(r *Request, f http.File) { files, err := f.Readdir(-1) if err != nil { diff --git a/net/ghttp/ghttp_server_log.go b/net/ghttp/ghttp_server_log.go index 92098a790..93e66dcb5 100644 --- a/net/ghttp/ghttp_server_log.go +++ b/net/ghttp/ghttp_server_log.go @@ -17,7 +17,7 @@ func (s *Server) Logger() *glog.Logger { return s.config.Logger } -// 处理服务错误信息,主要是panic,http请求的status由access log进行管理 +// handleAccessLog handles the access logging for server. func (s *Server) handleAccessLog(r *Request) { if !s.IsAccessLogEnabled() { return @@ -37,14 +37,13 @@ func (s *Server) handleAccessLog(r *Request) { ) } -// 处理服务错误信息,主要是panic,http请求的status由access log进行管理 +// handleErrorLog handles the error logging for server. func (s *Server) handleErrorLog(err error, r *Request) { - // 错误输出默认是开启的 + // It does nothing if error logging is custom disabled. if !s.IsErrorLogEnabled() { return } - // 错误日志信息 scheme := "http" if r.TLS != nil { scheme = "https" diff --git a/net/ghttp/ghttp_server_router_hook.go b/net/ghttp/ghttp_server_router_hook.go index c073a556d..a33a06141 100644 --- a/net/ghttp/ghttp_server_router_hook.go +++ b/net/ghttp/ghttp_server_router_hook.go @@ -11,7 +11,7 @@ import ( "net/http" ) -// 绑定指定的hook回调函数, pattern参数同BindHandler,支持命名路由;hook参数的值由ghttp server设定,参数不区分大小写 +// BindHookHandler registers handler for specified hook. func (s *Server) BindHookHandler(pattern string, hook string, handler HandlerFunc) { s.doBindHookHandler(pattern, hook, handler, "") } @@ -26,23 +26,22 @@ func (s *Server) doBindHookHandler(pattern string, hook string, handler HandlerF }) } -// 通过map批量绑定回调函数 func (s *Server) BindHookHandlerByMap(pattern string, hookMap map[string]HandlerFunc) { for k, v := range hookMap { s.BindHookHandler(pattern, k, v) } } -// 事件回调处理,内部使用了缓存处理. -// 并按照指定hook回调函数的优先级及注册顺序进行调用 +// callHookHandler calls the hook handler by their registered sequences. func (s *Server) callHookHandler(hook string, r *Request) { hookItems := r.getHookHandlers(hook) if len(hookItems) > 0 { - // 备份原有的router变量 + // Backup the old router variable map. oldRouterMap := r.routerMap for _, item := range hookItems { r.routerMap = item.values - // 不使用hook的router对象,保留路由注册服务的router对象,不能覆盖 + // DO NOT USE the router of the hook handler, + // which can overwrite the router of serving handler. // r.Router = item.handler.router if err := s.niceCallHookHandler(item.handler.itemFunc, r); err != nil { switch err { @@ -58,12 +57,12 @@ func (s *Server) callHookHandler(hook string, r *Request) { } } } - // 恢复原有的router变量 + // Restore the old router variable map. r.routerMap = oldRouterMap } } -// 获得当前请求,指定类型的的钩子函数列表 +// getHookHandlers retrieves and returns the hook handlers of specified hook. func (r *Request) getHookHandlers(hook string) []*handlerParsedItem { if !r.hasHookHandler { return nil @@ -79,7 +78,9 @@ func (r *Request) getHookHandlers(hook string) []*handlerParsedItem { return parsedItems } -// 友好地调用方法 +// niceCallHookHandler nicely calls the hook handler function, +// which means it automatically catches and returns the possible panic error to +// avoid goroutine crash. func (s *Server) niceCallHookHandler(f HandlerFunc, r *Request) (err interface{}) { defer func() { err = recover() diff --git a/net/ghttp/ghttp_server_session.go b/net/ghttp/ghttp_server_session.go index 3d7ec737a..5bf5ba200 100644 --- a/net/ghttp/ghttp_server_session.go +++ b/net/ghttp/ghttp_server_session.go @@ -8,4 +8,5 @@ package ghttp import "github.com/gogf/gf/os/gsession" +// Session is actually a alias of gsession.Session. type Session = gsession.Session diff --git a/net/ghttp/ghttp_server_websocket.go b/net/ghttp/ghttp_server_websocket.go index f327fc3e1..07d3a8bca 100644 --- a/net/ghttp/ghttp_server_websocket.go +++ b/net/ghttp/ghttp_server_websocket.go @@ -8,6 +8,8 @@ package ghttp import "github.com/gorilla/websocket" +// WebSocket wraps the underlying websocket connection +// and provides convenient functions. type WebSocket struct { *websocket.Conn } diff --git a/os/gcache/gcache_mem_cache.go b/os/gcache/gcache_mem_cache.go index 58d10c7c5..b1c39cdf0 100644 --- a/os/gcache/gcache_mem_cache.go +++ b/os/gcache/gcache_mem_cache.go @@ -431,7 +431,7 @@ func (c *memCache) syncEventAndClearExpired() { } // clearByKey deletes the key-value pair with given . -// The parameter specifies whether doing this deleting forcedly. +// The parameter specifies whether doing this deleting forcibly. func (c *memCache) clearByKey(key interface{}, force ...bool) { c.dataMu.Lock() // Doubly check before really deleting it from cache.