forked from aegis/pyserveX
feat: Add reverse proxy functionality with enhanced routing capabilities
- Introduced IgnoreRequestPath option in proxy configuration to allow exact match routing. - Implemented proxy_pass directive in routing extension to handle backend requests. - Enhanced error handling for backend unavailability and timeouts. - Added integration tests for reverse proxy, including basic requests, exact match routes, regex routes, header forwarding, and query string preservation. - Created helper functions for setting up test servers and backends, along with assertion utilities for response validation. - Updated server initialization to support extension management and middleware chaining. - Improved logging for debugging purposes during request handling.
This commit is contained in:
@@ -11,19 +11,19 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/konduktor/konduktor/internal/config"
|
||||
"github.com/konduktor/konduktor/internal/extension"
|
||||
"github.com/konduktor/konduktor/internal/logging"
|
||||
"github.com/konduktor/konduktor/internal/middleware"
|
||||
"github.com/konduktor/konduktor/internal/routing"
|
||||
)
|
||||
|
||||
const Version = "0.1.0"
|
||||
const Version = "0.2.0"
|
||||
|
||||
// Server represents the Konduktor HTTP server
|
||||
type Server struct {
|
||||
config *config.Config
|
||||
httpServer *http.Server
|
||||
router *routing.Router
|
||||
logger *logging.Logger
|
||||
config *config.Config
|
||||
httpServer *http.Server
|
||||
extensionManager *extension.Manager
|
||||
logger *logging.Logger
|
||||
}
|
||||
|
||||
// New creates a new server instance
|
||||
@@ -37,12 +37,31 @@ func New(cfg *config.Config) (*Server, error) {
|
||||
return nil, fmt.Errorf("failed to create logger: %w", err)
|
||||
}
|
||||
|
||||
router := routing.New(cfg, logger)
|
||||
// Create extension manager
|
||||
extManager := extension.NewManager(logger)
|
||||
|
||||
// Load extensions from config
|
||||
for _, extCfg := range cfg.Extensions {
|
||||
// Add static_dir to routing config if not present
|
||||
if extCfg.Type == "routing" {
|
||||
if extCfg.Config == nil {
|
||||
extCfg.Config = make(map[string]interface{})
|
||||
}
|
||||
if _, ok := extCfg.Config["static_dir"]; !ok {
|
||||
extCfg.Config["static_dir"] = cfg.HTTP.StaticDir
|
||||
}
|
||||
}
|
||||
|
||||
if err := extManager.LoadExtension(extCfg.Type, extCfg.Config); err != nil {
|
||||
logger.Error("Failed to load extension", "type", extCfg.Type, "error", err)
|
||||
// Continue loading other extensions
|
||||
}
|
||||
}
|
||||
|
||||
srv := &Server{
|
||||
config: cfg,
|
||||
router: router,
|
||||
logger: logger,
|
||||
config: cfg,
|
||||
extensionManager: extManager,
|
||||
logger: logger,
|
||||
}
|
||||
|
||||
return srv, nil
|
||||
@@ -86,9 +105,15 @@ func (s *Server) Run() error {
|
||||
|
||||
// buildHandler builds the HTTP handler chain
|
||||
func (s *Server) buildHandler() http.Handler {
|
||||
var handler http.Handler = s.router
|
||||
// Create base handler that returns 404
|
||||
baseHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
http.NotFound(w, r)
|
||||
})
|
||||
|
||||
// Add middleware
|
||||
// Wrap with extension manager
|
||||
var handler http.Handler = s.extensionManager.Handler(baseHandler)
|
||||
|
||||
// Add middleware (applied in reverse order)
|
||||
handler = middleware.AccessLog(handler, s.logger)
|
||||
handler = middleware.ServerHeader(handler, Version)
|
||||
handler = middleware.Recovery(handler, s.logger)
|
||||
@@ -115,6 +140,9 @@ func (s *Server) waitForShutdown(errChan <-chan error) error {
|
||||
|
||||
s.logger.Info("Shutting down server...")
|
||||
|
||||
// Cleanup extensions
|
||||
s.extensionManager.Cleanup()
|
||||
|
||||
if err := s.httpServer.Shutdown(ctx); err != nil {
|
||||
s.logger.Error("Error during shutdown", "error", err)
|
||||
return err
|
||||
|
||||
Reference in New Issue
Block a user