Skip to content

Commit

Permalink
feat: http server configurations with full controll
Browse files Browse the repository at this point in the history
  • Loading branch information
hokamsingh committed Sep 2, 2024
1 parent 8f8a27c commit 4e40ead
Show file tree
Hide file tree
Showing 5 changed files with 247 additions and 9 deletions.
File renamed without changes.
116 changes: 116 additions & 0 deletions internal/core/config/http.config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
package config

// HttpConfig holds the configuration options for the HTTP server.
type HttpConfig struct {
ReadTimeout int
WriteTimeout int
IdleTimeout int
MaxHeaderSize int
TLSCertFile string
TLSKeyFile string
Security SecurityConfig
Session SessionConfig
}

// SecurityConfig holds the security-related configuration options.
type SecurityConfig struct {
EnableHSTS bool
ContentSecurityPolicy string
}

// SessionConfig holds the session-related configuration options.
type SessionConfig struct {
Store string
Timeout int
}

// NewHttpConfig creates a new HttpConfig with optional settings.
// You can pass option functions to override default settings.
func NewHttpConfig(options ...func(*HttpConfig)) *HttpConfig {
// Set default values
cfg := &HttpConfig{
ReadTimeout: 5, // Default to 5 seconds
WriteTimeout: 5, // Default to 5 seconds
IdleTimeout: 120, // Default to 120 seconds
MaxHeaderSize: 1 << 20, // Default to 1 MB
TLSCertFile: "", // No default cert file
TLSKeyFile: "", // No default key file
Security: SecurityConfig{
EnableHSTS: true, // Default to enabling HSTS
ContentSecurityPolicy: "default-src 'self'", // Default CSP
},
Session: SessionConfig{
Store: "memory", // Default to in-memory store
Timeout: 3600, // Default to 1 hour
},
}

// Apply any provided options
for _, option := range options {
option(cfg)
}

return cfg
}

// Option functions

func WithReadTimeout(timeout int) func(*HttpConfig) {
return func(cfg *HttpConfig) {
cfg.ReadTimeout = timeout
}
}

func WithWriteTimeout(timeout int) func(*HttpConfig) {
return func(cfg *HttpConfig) {
cfg.WriteTimeout = timeout
}
}

func WithIdleTimeout(timeout int) func(*HttpConfig) {
return func(cfg *HttpConfig) {
cfg.IdleTimeout = timeout
}
}

func WithMaxHeaderSize(size int) func(*HttpConfig) {
return func(cfg *HttpConfig) {
cfg.MaxHeaderSize = size
}
}

func WithTLSCertFile(certFile string) func(*HttpConfig) {
return func(cfg *HttpConfig) {
cfg.TLSCertFile = certFile
}
}

func WithTLSKeyFile(keyFile string) func(*HttpConfig) {
return func(cfg *HttpConfig) {
cfg.TLSKeyFile = keyFile
}
}

func WithHSTS(enabled bool) func(*HttpConfig) {
return func(cfg *HttpConfig) {
cfg.Security.EnableHSTS = enabled
}
}

func WithContentSecurityPolicy(policy string) func(*HttpConfig) {
return func(cfg *HttpConfig) {
cfg.Security.ContentSecurityPolicy = policy
}
}

func WithSessionStore(store string) func(*HttpConfig) {
return func(cfg *HttpConfig) {
cfg.Session.Store = store
}
}

func WithSessionTimeout(timeout int) func(*HttpConfig) {
return func(cfg *HttpConfig) {
cfg.Session.Timeout = timeout
}
}
5 changes: 3 additions & 2 deletions internal/core/factory/factory.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package factory

import (
"github.com/hokamsingh/lessgo/internal/core/config"
"github.com/hokamsingh/lessgo/internal/core/di"
"github.com/hokamsingh/lessgo/internal/core/router"
)
Expand All @@ -20,6 +21,6 @@ func NewApp(router *router.Router, container *di.Container) *App {
}

// Start the HTTP server on the specified address
func (app *App) Start(addr string) error {
return app.Router.Listen(addr)
func (app *App) Start(addr string, httpConfig *config.HttpConfig) error {
return app.Router.Listen(addr, httpConfig)
}
41 changes: 34 additions & 7 deletions internal/core/router/router.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package router

import (
"crypto/tls"
"encoding/json"
"encoding/xml"
"fmt"
Expand All @@ -14,6 +15,7 @@ import (

"github.com/go-redis/redis/v8"
"github.com/gorilla/mux"
"github.com/hokamsingh/lessgo/internal/core/config"
"github.com/hokamsingh/lessgo/internal/core/context"
"github.com/hokamsingh/lessgo/internal/core/middleware"
"github.com/hokamsingh/lessgo/internal/utils"
Expand Down Expand Up @@ -354,7 +356,7 @@ func (r *Router) AddRoute(path string, handler CustomHandler) {
// if err != nil {
// log.Fatalf("Server failed: %v", err)
// }
func (r *Router) Start(addr string) error {
func (r *Router) Start(addr string, httpConfig *config.HttpConfig) error {
// Apply middlewares
finalHandler := http.Handler(r.Mux)
for _, m := range r.middleware {
Expand All @@ -364,21 +366,46 @@ func (r *Router) Start(addr string) error {
server := &http.Server{
Addr: addr,
Handler: finalHandler,
ReadTimeout: 5 * time.Second, // Defaults timeout
WriteTimeout: 10 * time.Second, // Defaults timeout
IdleTimeout: 120 * time.Second, // Defaults timeout
ReadTimeout: time.Duration(httpConfig.ReadTimeout) * time.Second, // Set read timeout
WriteTimeout: time.Duration(httpConfig.WriteTimeout) * time.Second, // Set write timeout
IdleTimeout: time.Duration(httpConfig.IdleTimeout) * time.Second, // Set idle timeout
// Set maximum header size
MaxHeaderBytes: httpConfig.MaxHeaderSize,
}

// Configure TLS if certificates are provided
if httpConfig.TLSCertFile != "" && httpConfig.TLSKeyFile != "" {
server.TLSConfig = &tls.Config{
MinVersion: tls.VersionTLS12, // Example of configuring TLS settings
}

// Enable HSTS if configured
if httpConfig.Security.EnableHSTS {
finalHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Strict-Transport-Security", "max-age=63072000; includeSubDomains")
finalHandler.ServeHTTP(w, r)
})
}

// Start HTTPS server with TLS
err := server.ListenAndServeTLS(httpConfig.TLSCertFile, httpConfig.TLSKeyFile)
if err != nil {
log.Fatalf("HTTPS server failed: %v", err)
}
return err
}

// Start HTTP server if TLS is not configured
err := server.ListenAndServe()
if err != nil {
log.Fatalf("Server failed: %v", err)
log.Fatalf("HTTP server failed: %v", err)
}
return err
}

// Start http server
func (r *Router) Listen(addr string) error {
return r.Start(addr)
func (r *Router) Listen(addr string, httpConfig *config.HttpConfig) error {
return r.Start(addr, httpConfig)
}

// HTTPError represents an error with an associated HTTP status code.
Expand Down
94 changes: 94 additions & 0 deletions pkg/lessgo/less.go
Original file line number Diff line number Diff line change
Expand Up @@ -491,3 +491,97 @@ func ConvertToBytes(size int64, unit SizeUnit) int64 {
func NewRedisClient(redisAddr string) *redis.Client {
return utils.NewRedisClient(redisAddr)
}

type HttpConfig = config.HttpConfig

// NewHttpConfig creates a new HttpConfig instance with optional configuration options.
// This function accepts a variadic number of option functions that allow customization
// of the HttpConfig fields. If no options are provided, it will create a configuration
// with default values for all fields.
//
// Default values:
// - ReadTimeout: 10 seconds
// - WriteTimeout: 10 seconds
// - IdleTimeout: 60 seconds
// - MaxHeaderSize: 1 MB (1048576 bytes)
// - TLSCertFile: "" (empty string, no certificate file)
// - TLSKeyFile: "" (empty string, no key file)
// - Security.EnableHSTS: false
// - Security.ContentSecurityPolicy: "" (empty string, no policy)
// - Session.Store: "memory" (default session store)
// - Session.Timeout: 3600 seconds (1 hour)
//
// The options functions should be used to set various fields of the HttpConfig,
// such as timeouts, TLS certificates, and security settings. Each option function
// takes a pointer to HttpConfig and modifies it accordingly.
//
// Example usage:
//
// cfg := LessGo.NewHttpConfig(
// LessGo.WithReadTimeout(30),
// LessGo.WithWriteTimeout(30),
// LessGo.WithTLSCertFile("/path/to/cert.pem"),
// )
//
// Parameters:
// - options: A variadic number of option functions that modify the HttpConfig instance.
//
// Returns:
// - *HttpConfig: A pointer to the newly created HttpConfig instance with applied options.
//
// See also:
// - WithReadTimeout
// - WithWriteTimeout
// - WithTLSCertFile
func NewHttpConfig(options ...func(*config.HttpConfig)) *config.HttpConfig {
return config.NewHttpConfig()
}

func WithReadTimeout(timeout int) func(*config.HttpConfig) {
return config.WithReadTimeout(timeout)
}

// Wrapper for WithWriteTimeout
func WithWriteTimeout(timeout int) func(*HttpConfig) {
return config.WithWriteTimeout(timeout)
}

// Wrapper for WithIdleTimeout
func WithIdleTimeout(timeout int) func(*HttpConfig) {
return config.WithIdleTimeout(timeout)
}

// Wrapper for WithMaxHeaderSize
func WithMaxHeaderSize(size int) func(*HttpConfig) {
return config.WithMaxHeaderSize(size)
}

// Wrapper for WithTLSCertFile
func WithTLSCertFile(certFile string) func(*HttpConfig) {
return config.WithTLSCertFile(certFile)
}

// Wrapper for WithTLSKeyFile
func WithTLSKeyFile(keyFile string) func(*HttpConfig) {
return config.WithTLSKeyFile(keyFile)
}

// Wrapper for WithHSTS
func WithHSTS(enabled bool) func(*HttpConfig) {
return config.WithHSTS(enabled)
}

// Wrapper for WithContentSecurityPolicy
func WithContentSecurityPolicy(policy string) func(*HttpConfig) {
return config.WithContentSecurityPolicy(policy)
}

// Wrapper for WithSessionStore
func WithSessionStore(store string) func(*HttpConfig) {
return config.WithSessionStore(store)
}

// Wrapper for WithSessionTimeout
func WithSessionTimeout(timeout int) func(*HttpConfig) {
return config.WithSessionTimeout(timeout)
}

0 comments on commit 4e40ead

Please sign in to comment.