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