github.com/wangyougui/gf/v2@v2.6.5/net/ghttp/ghttp_server_config.go (about) 1 // Copyright GoFrame Author(https://goframe.org). All Rights Reserved. 2 // 3 // This Source Code Form is subject to the terms of the MIT License. 4 // If a copy of the MIT was not distributed with this file, 5 // You can obtain one at https://github.com/wangyougui/gf. 6 7 package ghttp 8 9 import ( 10 "context" 11 "crypto/tls" 12 "fmt" 13 "net" 14 "net/http" 15 "strconv" 16 "strings" 17 "time" 18 19 "github.com/wangyougui/gf/v2/errors/gcode" 20 "github.com/wangyougui/gf/v2/errors/gerror" 21 "github.com/wangyougui/gf/v2/internal/intlog" 22 "github.com/wangyougui/gf/v2/net/gsvc" 23 "github.com/wangyougui/gf/v2/os/gfile" 24 "github.com/wangyougui/gf/v2/os/glog" 25 "github.com/wangyougui/gf/v2/os/gres" 26 "github.com/wangyougui/gf/v2/os/gsession" 27 "github.com/wangyougui/gf/v2/os/gview" 28 "github.com/wangyougui/gf/v2/text/gstr" 29 "github.com/wangyougui/gf/v2/util/gconv" 30 "github.com/wangyougui/gf/v2/util/gutil" 31 ) 32 33 const ( 34 defaultHttpAddr = ":80" // Default listening port for HTTP. 35 defaultHttpsAddr = ":443" // Default listening port for HTTPS. 36 37 ) 38 39 const ( 40 UriTypeDefault = iota // Method names to the URI converting type, which converts name to its lower case and joins the words using char '-'. 41 UriTypeFullName // Method names to the URI converting type, which does not convert to the method name. 42 UriTypeAllLower // Method names to the URI converting type, which converts name to its lower case. 43 UriTypeCamel // Method names to the URI converting type, which converts name to its camel case. 44 ) 45 46 // ServerConfig is the HTTP Server configuration manager. 47 type ServerConfig struct { 48 // ====================================================================================================== 49 // Basic. 50 // ====================================================================================================== 51 52 // Service name, which is for service registry and discovery. 53 Name string `json:"name"` 54 55 // Address specifies the server listening address like "port" or ":port", 56 // multiple addresses joined using ','. 57 Address string `json:"address"` 58 59 // HTTPSAddr specifies the HTTPS addresses, multiple addresses joined using char ','. 60 HTTPSAddr string `json:"httpsAddr"` 61 62 // Listeners specifies the custom listeners. 63 Listeners []net.Listener `json:"listeners"` 64 65 // Endpoints are custom endpoints for service register, it uses Address if empty. 66 Endpoints []string `json:"endpoints"` 67 68 // HTTPSCertPath specifies certification file path for HTTPS service. 69 HTTPSCertPath string `json:"httpsCertPath"` 70 71 // HTTPSKeyPath specifies the key file path for HTTPS service. 72 HTTPSKeyPath string `json:"httpsKeyPath"` 73 74 // TLSConfig optionally provides a TLS configuration for use 75 // by ServeTLS and ListenAndServeTLS. Note that this value is 76 // cloned by ServeTLS and ListenAndServeTLS, so it's not 77 // possible to modify the configuration with methods like 78 // tls.Config.SetSessionTicketKeys. To use 79 // SetSessionTicketKeys, use Server.Serve with a TLS Listener 80 // instead. 81 TLSConfig *tls.Config `json:"tlsConfig"` 82 83 // Handler the handler for HTTP request. 84 Handler func(w http.ResponseWriter, r *http.Request) `json:"-"` 85 86 // ReadTimeout is the maximum duration for reading the entire 87 // request, including the body. 88 // 89 // Because ReadTimeout does not let Handlers make per-request 90 // decisions on each request body's acceptable deadline or 91 // upload rate, most users will prefer to use 92 // ReadHeaderTimeout. It is valid to use them both. 93 ReadTimeout time.Duration `json:"readTimeout"` 94 95 // WriteTimeout is the maximum duration before timing out 96 // writes of the response. It is reset whenever a new 97 // request's header is read. Like ReadTimeout, it does not 98 // let Handlers make decisions on a per-request basis. 99 WriteTimeout time.Duration `json:"writeTimeout"` 100 101 // IdleTimeout is the maximum amount of time to wait for the 102 // next request when keep-alive are enabled. If IdleTimeout 103 // is zero, the value of ReadTimeout is used. If both are 104 // zero, there is no timeout. 105 IdleTimeout time.Duration `json:"idleTimeout"` 106 107 // MaxHeaderBytes controls the maximum number of bytes the 108 // server will read parsing the request header's keys and 109 // values, including the request line. It does not limit the 110 // size of the request body. 111 // 112 // It can be configured in configuration file using string like: 1m, 10m, 500kb etc. 113 // It's 10240 bytes in default. 114 MaxHeaderBytes int `json:"maxHeaderBytes"` 115 116 // KeepAlive enables HTTP keep-alive. 117 KeepAlive bool `json:"keepAlive"` 118 119 // ServerAgent specifies the server agent information, which is wrote to 120 // HTTP response header as "Server". 121 ServerAgent string `json:"serverAgent"` 122 123 // View specifies the default template view object for the server. 124 View *gview.View `json:"view"` 125 126 // ====================================================================================================== 127 // Static. 128 // ====================================================================================================== 129 130 // Rewrites specifies the URI rewrite rules map. 131 Rewrites map[string]string `json:"rewrites"` 132 133 // IndexFiles specifies the index files for static folder. 134 IndexFiles []string `json:"indexFiles"` 135 136 // IndexFolder specifies if listing sub-files when requesting folder. 137 // The server responses HTTP status code 403 if it is false. 138 IndexFolder bool `json:"indexFolder"` 139 140 // ServerRoot specifies the root directory for static service. 141 ServerRoot string `json:"serverRoot"` 142 143 // SearchPaths specifies additional searching directories for static service. 144 SearchPaths []string `json:"searchPaths"` 145 146 // StaticPaths specifies URI to directory mapping array. 147 StaticPaths []staticPathItem `json:"staticPaths"` 148 149 // FileServerEnabled is the global switch for static service. 150 // It is automatically set enabled if any static path is set. 151 FileServerEnabled bool `json:"fileServerEnabled"` 152 153 // ====================================================================================================== 154 // Cookie. 155 // ====================================================================================================== 156 157 // CookieMaxAge specifies the max TTL for cookie items. 158 CookieMaxAge time.Duration `json:"cookieMaxAge"` 159 160 // CookiePath specifies cookie path. 161 // It also affects the default storage for session id. 162 CookiePath string `json:"cookiePath"` 163 164 // CookieDomain specifies cookie domain. 165 // It also affects the default storage for session id. 166 CookieDomain string `json:"cookieDomain"` 167 168 // CookieSameSite specifies cookie SameSite property. 169 // It also affects the default storage for session id. 170 CookieSameSite string `json:"cookieSameSite"` 171 172 // CookieSameSite specifies cookie Secure property. 173 // It also affects the default storage for session id. 174 CookieSecure bool `json:"cookieSecure"` 175 176 // CookieSameSite specifies cookie HttpOnly property. 177 // It also affects the default storage for session id. 178 CookieHttpOnly bool `json:"cookieHttpOnly"` 179 180 // ====================================================================================================== 181 // Session. 182 // ====================================================================================================== 183 184 // SessionIdName specifies the session id name. 185 SessionIdName string `json:"sessionIdName"` 186 187 // SessionMaxAge specifies max TTL for session items. 188 SessionMaxAge time.Duration `json:"sessionMaxAge"` 189 190 // SessionPath specifies the session storage directory path for storing session files. 191 // It only makes sense if the session storage is type of file storage. 192 SessionPath string `json:"sessionPath"` 193 194 // SessionStorage specifies the session storage. 195 SessionStorage gsession.Storage `json:"sessionStorage"` 196 197 // SessionCookieMaxAge specifies the cookie ttl for session id. 198 // If it is set 0, it means it expires along with browser session. 199 SessionCookieMaxAge time.Duration `json:"sessionCookieMaxAge"` 200 201 // SessionCookieOutput specifies whether automatic outputting session id to cookie. 202 SessionCookieOutput bool `json:"sessionCookieOutput"` 203 204 // ====================================================================================================== 205 // Logging. 206 // ====================================================================================================== 207 208 Logger *glog.Logger `json:"logger"` // Logger specifies the logger for server. 209 LogPath string `json:"logPath"` // LogPath specifies the directory for storing logging files. 210 LogLevel string `json:"logLevel"` // LogLevel specifies the logging level for logger. 211 LogStdout bool `json:"logStdout"` // LogStdout specifies whether printing logging content to stdout. 212 ErrorStack bool `json:"errorStack"` // ErrorStack specifies whether logging stack information when error. 213 ErrorLogEnabled bool `json:"errorLogEnabled"` // ErrorLogEnabled enables error logging content to files. 214 ErrorLogPattern string `json:"errorLogPattern"` // ErrorLogPattern specifies the error log file pattern like: error-{Ymd}.log 215 AccessLogEnabled bool `json:"accessLogEnabled"` // AccessLogEnabled enables access logging content to files. 216 AccessLogPattern string `json:"accessLogPattern"` // AccessLogPattern specifies the error log file pattern like: access-{Ymd}.log 217 218 // ====================================================================================================== 219 // PProf. 220 // ====================================================================================================== 221 222 PProfEnabled bool `json:"pprofEnabled"` // PProfEnabled enables PProf feature. 223 PProfPattern string `json:"pprofPattern"` // PProfPattern specifies the PProf service pattern for router. 224 225 // ====================================================================================================== 226 // API & Swagger. 227 // ====================================================================================================== 228 229 OpenApiPath string `json:"openapiPath"` // OpenApiPath specifies the OpenApi specification file path. 230 SwaggerPath string `json:"swaggerPath"` // SwaggerPath specifies the swagger UI path for route registering. 231 SwaggerUITemplate string `json:"swaggerUITemplate"` // SwaggerUITemplate specifies the swagger UI custom template 232 233 // ====================================================================================================== 234 // Other. 235 // ====================================================================================================== 236 237 // ClientMaxBodySize specifies the max body size limit in bytes for client request. 238 // It can be configured in configuration file using string like: 1m, 10m, 500kb etc. 239 // It's `8MB` in default. 240 ClientMaxBodySize int64 `json:"clientMaxBodySize"` 241 242 // FormParsingMemory specifies max memory buffer size in bytes which can be used for 243 // parsing multimedia form. 244 // It can be configured in configuration file using string like: 1m, 10m, 500kb etc. 245 // It's 1MB in default. 246 FormParsingMemory int64 `json:"formParsingMemory"` 247 248 // NameToUriType specifies the type for converting struct method name to URI when 249 // registering routes. 250 NameToUriType int `json:"nameToUriType"` 251 252 // RouteOverWrite allows to overwrite the route if duplicated. 253 RouteOverWrite bool `json:"routeOverWrite"` 254 255 // DumpRouterMap specifies whether automatically dumps router map when server starts. 256 DumpRouterMap bool `json:"dumpRouterMap"` 257 258 // Graceful enables graceful reload feature for all servers of the process. 259 Graceful bool `json:"graceful"` 260 261 // GracefulTimeout set the maximum survival time (seconds) of the parent process. 262 GracefulTimeout uint8 `json:"gracefulTimeout"` 263 264 // GracefulShutdownTimeout set the maximum survival time (seconds) before stopping the server. 265 GracefulShutdownTimeout uint8 `json:"gracefulShutdownTimeout"` 266 } 267 268 // NewConfig creates and returns a ServerConfig object with default configurations. 269 // Note that, do not define this default configuration to local package variable, as there are 270 // some pointer attributes that may be shared in different servers. 271 func NewConfig() ServerConfig { 272 return ServerConfig{ 273 Name: DefaultServerName, 274 Address: ":0", 275 HTTPSAddr: "", 276 Listeners: nil, 277 Handler: nil, 278 ReadTimeout: 60 * time.Second, 279 WriteTimeout: 0, // No timeout. 280 IdleTimeout: 60 * time.Second, 281 MaxHeaderBytes: 10240, // 10KB 282 KeepAlive: true, 283 IndexFiles: []string{"index.html", "index.htm"}, 284 IndexFolder: false, 285 ServerAgent: "GoFrame HTTP Server", 286 ServerRoot: "", 287 StaticPaths: make([]staticPathItem, 0), 288 FileServerEnabled: false, 289 CookieMaxAge: time.Hour * 24 * 365, 290 CookiePath: "/", 291 CookieDomain: "", 292 SessionIdName: "gfsessionid", 293 SessionPath: gsession.DefaultStorageFilePath, 294 SessionMaxAge: time.Hour * 24, 295 SessionCookieOutput: true, 296 SessionCookieMaxAge: time.Hour * 24, 297 Logger: glog.New(), 298 LogLevel: "all", 299 LogStdout: true, 300 ErrorStack: true, 301 ErrorLogEnabled: true, 302 ErrorLogPattern: "error-{Ymd}.log", 303 AccessLogEnabled: false, 304 AccessLogPattern: "access-{Ymd}.log", 305 DumpRouterMap: true, 306 ClientMaxBodySize: 8 * 1024 * 1024, // 8MB 307 FormParsingMemory: 1024 * 1024, // 1MB 308 Rewrites: make(map[string]string), 309 Graceful: false, 310 GracefulTimeout: 2, // seconds 311 GracefulShutdownTimeout: 5, // seconds 312 } 313 } 314 315 // ConfigFromMap creates and returns a ServerConfig object with given map and 316 // default configuration object. 317 func ConfigFromMap(m map[string]interface{}) (ServerConfig, error) { 318 config := NewConfig() 319 if err := gconv.Struct(m, &config); err != nil { 320 return config, err 321 } 322 return config, nil 323 } 324 325 // SetConfigWithMap sets the configuration for the server using map. 326 func (s *Server) SetConfigWithMap(m map[string]interface{}) error { 327 // The m now is a shallow copy of m. 328 // Any changes to m does not affect the original one. 329 // A little tricky, isn't it? 330 m = gutil.MapCopy(m) 331 // Allow setting the size configuration items using string size like: 332 // 1m, 100mb, 512kb, etc. 333 if k, v := gutil.MapPossibleItemByKey(m, "MaxHeaderBytes"); k != "" { 334 m[k] = gfile.StrToSize(gconv.String(v)) 335 } 336 if k, v := gutil.MapPossibleItemByKey(m, "ClientMaxBodySize"); k != "" { 337 m[k] = gfile.StrToSize(gconv.String(v)) 338 } 339 if k, v := gutil.MapPossibleItemByKey(m, "FormParsingMemory"); k != "" { 340 m[k] = gfile.StrToSize(gconv.String(v)) 341 } 342 // Update the current configuration object. 343 // It only updates the configured keys not all the object. 344 if err := gconv.Struct(m, &s.config); err != nil { 345 return err 346 } 347 return s.SetConfig(s.config) 348 } 349 350 // SetConfig sets the configuration for the server. 351 func (s *Server) SetConfig(c ServerConfig) error { 352 s.config = c 353 // Automatically add ':' prefix for address if it is missed. 354 if s.config.Address != "" && !gstr.Contains(s.config.Address, ":") { 355 s.config.Address = ":" + s.config.Address 356 } 357 // Static files root. 358 if c.ServerRoot != "" { 359 s.SetServerRoot(c.ServerRoot) 360 } 361 if len(c.SearchPaths) > 0 { 362 paths := c.SearchPaths 363 c.SearchPaths = []string{} 364 for _, v := range paths { 365 s.AddSearchPath(v) 366 } 367 } 368 // HTTPS. 369 if c.TLSConfig == nil && c.HTTPSCertPath != "" { 370 s.EnableHTTPS(c.HTTPSCertPath, c.HTTPSKeyPath) 371 } 372 // Logging. 373 if s.config.LogPath != "" && s.config.LogPath != s.config.Logger.GetPath() { 374 if err := s.config.Logger.SetPath(s.config.LogPath); err != nil { 375 return err 376 } 377 } 378 if err := s.config.Logger.SetLevelStr(s.config.LogLevel); err != nil { 379 intlog.Errorf(context.TODO(), `%+v`, err) 380 } 381 gracefulEnabled = c.Graceful 382 intlog.Printf(context.TODO(), "SetConfig: %+v", s.config) 383 return nil 384 } 385 386 // SetAddr sets the listening address for the server. 387 // The address is like ':80', '0.0.0.0:80', '127.0.0.1:80', '180.18.99.10:80', etc. 388 func (s *Server) SetAddr(address string) { 389 s.config.Address = address 390 } 391 392 // SetPort sets the listening ports for the server. 393 // The listening ports can be multiple like: SetPort(80, 8080). 394 func (s *Server) SetPort(port ...int) { 395 if len(port) > 0 { 396 s.config.Address = "" 397 for _, v := range port { 398 if len(s.config.Address) > 0 { 399 s.config.Address += "," 400 } 401 s.config.Address += ":" + strconv.Itoa(v) 402 } 403 } 404 } 405 406 // SetHTTPSAddr sets the HTTPS listening ports for the server. 407 func (s *Server) SetHTTPSAddr(address string) { 408 s.config.HTTPSAddr = address 409 } 410 411 // SetHTTPSPort sets the HTTPS listening ports for the server. 412 // The listening ports can be multiple like: SetHTTPSPort(443, 500). 413 func (s *Server) SetHTTPSPort(port ...int) { 414 if len(port) > 0 { 415 s.config.HTTPSAddr = "" 416 for _, v := range port { 417 if len(s.config.HTTPSAddr) > 0 { 418 s.config.HTTPSAddr += "," 419 } 420 s.config.HTTPSAddr += ":" + strconv.Itoa(v) 421 } 422 } 423 } 424 425 // SetListener set the custom listener for the server. 426 func (s *Server) SetListener(listeners ...net.Listener) error { 427 if listeners == nil { 428 return gerror.NewCodef(gcode.CodeInvalidParameter, "SetListener failed: listener can not be nil") 429 } 430 if len(listeners) > 0 { 431 ports := make([]string, len(listeners)) 432 for k, v := range listeners { 433 if v == nil { 434 return gerror.NewCodef(gcode.CodeInvalidParameter, "SetListener failed: listener can not be nil") 435 } 436 ports[k] = fmt.Sprintf(":%d", (v.Addr().(*net.TCPAddr)).Port) 437 } 438 s.config.Address = strings.Join(ports, ",") 439 s.config.Listeners = listeners 440 } 441 return nil 442 } 443 444 // EnableHTTPS enables HTTPS with given certification and key files for the server. 445 // The optional parameter `tlsConfig` specifies custom TLS configuration. 446 func (s *Server) EnableHTTPS(certFile, keyFile string, tlsConfig ...*tls.Config) { 447 var ctx = context.TODO() 448 certFileRealPath := gfile.RealPath(certFile) 449 if certFileRealPath == "" { 450 certFileRealPath = gfile.RealPath(gfile.Pwd() + gfile.Separator + certFile) 451 if certFileRealPath == "" { 452 certFileRealPath = gfile.RealPath(gfile.MainPkgPath() + gfile.Separator + certFile) 453 } 454 } 455 // Resource. 456 if certFileRealPath == "" && gres.Contains(certFile) { 457 certFileRealPath = certFile 458 } 459 if certFileRealPath == "" { 460 s.Logger().Fatalf(ctx, `EnableHTTPS failed: certFile "%s" does not exist`, certFile) 461 } 462 keyFileRealPath := gfile.RealPath(keyFile) 463 if keyFileRealPath == "" { 464 keyFileRealPath = gfile.RealPath(gfile.Pwd() + gfile.Separator + keyFile) 465 if keyFileRealPath == "" { 466 keyFileRealPath = gfile.RealPath(gfile.MainPkgPath() + gfile.Separator + keyFile) 467 } 468 } 469 // Resource. 470 if keyFileRealPath == "" && gres.Contains(keyFile) { 471 keyFileRealPath = keyFile 472 } 473 if keyFileRealPath == "" { 474 s.Logger().Fatal(ctx, `EnableHTTPS failed: keyFile "%s" does not exist`, keyFile) 475 } 476 s.config.HTTPSCertPath = certFileRealPath 477 s.config.HTTPSKeyPath = keyFileRealPath 478 if len(tlsConfig) > 0 { 479 s.config.TLSConfig = tlsConfig[0] 480 } 481 } 482 483 // SetTLSConfig sets custom TLS configuration and enables HTTPS feature for the server. 484 func (s *Server) SetTLSConfig(tlsConfig *tls.Config) { 485 s.config.TLSConfig = tlsConfig 486 } 487 488 // SetReadTimeout sets the ReadTimeout for the server. 489 func (s *Server) SetReadTimeout(t time.Duration) { 490 s.config.ReadTimeout = t 491 } 492 493 // SetWriteTimeout sets the WriteTimeout for the server. 494 func (s *Server) SetWriteTimeout(t time.Duration) { 495 s.config.WriteTimeout = t 496 } 497 498 // SetIdleTimeout sets the IdleTimeout for the server. 499 func (s *Server) SetIdleTimeout(t time.Duration) { 500 s.config.IdleTimeout = t 501 } 502 503 // SetMaxHeaderBytes sets the MaxHeaderBytes for the server. 504 func (s *Server) SetMaxHeaderBytes(b int) { 505 s.config.MaxHeaderBytes = b 506 } 507 508 // SetServerAgent sets the ServerAgent for the server. 509 func (s *Server) SetServerAgent(agent string) { 510 s.config.ServerAgent = agent 511 } 512 513 // SetKeepAlive sets the KeepAlive for the server. 514 func (s *Server) SetKeepAlive(enabled bool) { 515 s.config.KeepAlive = enabled 516 } 517 518 // SetView sets the View for the server. 519 func (s *Server) SetView(view *gview.View) { 520 s.config.View = view 521 } 522 523 // GetName returns the name of the server. 524 func (s *Server) GetName() string { 525 return s.config.Name 526 } 527 528 // SetName sets the name for the server. 529 func (s *Server) SetName(name string) { 530 s.config.Name = name 531 } 532 533 // SetEndpoints sets the Endpoints for the server. 534 func (s *Server) SetEndpoints(endpoints []string) { 535 s.config.Endpoints = endpoints 536 } 537 538 // SetHandler sets the request handler for server. 539 func (s *Server) SetHandler(h func(w http.ResponseWriter, r *http.Request)) { 540 s.config.Handler = h 541 } 542 543 // GetHandler returns the request handler of the server. 544 func (s *Server) GetHandler() func(w http.ResponseWriter, r *http.Request) { 545 if s.config.Handler == nil { 546 return s.ServeHTTP 547 } 548 return s.config.Handler 549 } 550 551 // SetRegistrar sets the Registrar for server. 552 func (s *Server) SetRegistrar(registrar gsvc.Registrar) { 553 s.registrar = registrar 554 } 555 556 // GetRegistrar returns the Registrar of server. 557 func (s *Server) GetRegistrar() gsvc.Registrar { 558 return s.registrar 559 }