forked from aegis/pyserveX
- Added functionality to mark responses as cache hits to prevent incorrect X-Cache headers. - Introduced setCacheHitFlag function to traverse response writer wrappers and set cache hit flag. - Updated cachingResponseWriter to manage cache hit state and adjust X-Cache header accordingly. - Enhanced ProcessRequest and ProcessResponse methods to utilize new caching logic. feat(extension): Introduce ResponseWriterWrapper and ResponseFinalizer interfaces - Added ResponseWriterWrapper interface for extensions to wrap response writers. - Introduced ResponseFinalizer interface for finalizing responses after processing. refactor(manager): Improve response writer wrapping and finalization - Updated Manager.Handler to wrap response writers through all enabled extensions. - Implemented finalization of response writers after processing requests. test(caching): Add comprehensive integration tests for caching behavior - Created caching_test.go with tests for cache hit/miss, TTL expiration, pattern-based caching, and more. - Ensured that caching logic works correctly for various scenarios including query strings and error responses. test(routing): Add integration tests for routing behavior - Created routing_test.go with tests for route priority, case sensitivity, default routes, and return directives. - Verified that routing behaves as expected with multiple regex routes and named groups.
124 lines
3.5 KiB
Go
124 lines
3.5 KiB
Go
package extension
|
|
|
|
import (
|
|
"context"
|
|
"net/http"
|
|
|
|
"github.com/konduktor/konduktor/internal/logging"
|
|
)
|
|
|
|
// Extension is the interface that all extensions must implement
|
|
type Extension interface {
|
|
// Name returns the unique name of the extension
|
|
Name() string
|
|
|
|
// Initialize is called when the extension is loaded
|
|
Initialize() error
|
|
|
|
// ProcessRequest processes an incoming request before routing.
|
|
// Returns:
|
|
// - response: if non-nil, the request is handled and no further processing occurs
|
|
// - handled: if true, the request was handled by this extension
|
|
// - err: any error that occurred
|
|
ProcessRequest(ctx context.Context, w http.ResponseWriter, r *http.Request) (handled bool, err error)
|
|
|
|
// ProcessResponse is called after the response is generated but before it's sent.
|
|
// Extensions can modify the response here.
|
|
ProcessResponse(ctx context.Context, w http.ResponseWriter, r *http.Request)
|
|
|
|
// Cleanup is called when the extension is being unloaded
|
|
Cleanup() error
|
|
|
|
// Enabled returns whether the extension is currently enabled
|
|
Enabled() bool
|
|
|
|
// SetEnabled enables or disables the extension
|
|
SetEnabled(enabled bool)
|
|
|
|
// Priority returns the extension's priority (lower = earlier execution)
|
|
Priority() int
|
|
}
|
|
|
|
// BaseExtension provides a default implementation for common Extension methods
|
|
type BaseExtension struct {
|
|
name string
|
|
enabled bool
|
|
priority int
|
|
logger *logging.Logger
|
|
}
|
|
|
|
// NewBaseExtension creates a new BaseExtension
|
|
func NewBaseExtension(name string, priority int, logger *logging.Logger) BaseExtension {
|
|
return BaseExtension{
|
|
name: name,
|
|
enabled: true,
|
|
priority: priority,
|
|
logger: logger,
|
|
}
|
|
}
|
|
|
|
// Name returns the extension name
|
|
func (b *BaseExtension) Name() string {
|
|
return b.name
|
|
}
|
|
|
|
// Enabled returns whether the extension is enabled
|
|
func (b *BaseExtension) Enabled() bool {
|
|
return b.enabled
|
|
}
|
|
|
|
// SetEnabled sets the enabled state
|
|
func (b *BaseExtension) SetEnabled(enabled bool) {
|
|
b.enabled = enabled
|
|
}
|
|
|
|
// Priority returns the extension priority
|
|
func (b *BaseExtension) Priority() int {
|
|
return b.priority
|
|
}
|
|
|
|
// Initialize default implementation (no-op)
|
|
func (b *BaseExtension) Initialize() error {
|
|
return nil
|
|
}
|
|
|
|
// Cleanup default implementation (no-op)
|
|
func (b *BaseExtension) Cleanup() error {
|
|
return nil
|
|
}
|
|
|
|
// ProcessRequest default implementation (pass-through)
|
|
func (b *BaseExtension) ProcessRequest(ctx context.Context, w http.ResponseWriter, r *http.Request) (bool, error) {
|
|
return false, nil
|
|
}
|
|
|
|
// ProcessResponse default implementation (no-op)
|
|
func (b *BaseExtension) ProcessResponse(ctx context.Context, w http.ResponseWriter, r *http.Request) {
|
|
}
|
|
|
|
// Logger returns the extension's logger
|
|
func (b *BaseExtension) Logger() *logging.Logger {
|
|
return b.logger
|
|
}
|
|
|
|
// ExtensionConfig holds configuration for creating extensions
|
|
type ExtensionConfig struct {
|
|
Type string
|
|
Config map[string]interface{}
|
|
}
|
|
|
|
// ExtensionFactory is a function that creates an extension from config
|
|
type ExtensionFactory func(config map[string]interface{}, logger *logging.Logger) (Extension, error)
|
|
|
|
// ResponseWriterWrapper is an optional interface that extensions can implement
|
|
// to wrap the response writer for capturing/modifying responses
|
|
type ResponseWriterWrapper interface {
|
|
WrapResponseWriter(w http.ResponseWriter, r *http.Request) http.ResponseWriter
|
|
}
|
|
|
|
// ResponseFinalizer is an optional interface for response writers that need
|
|
// to perform finalization after the response is written (e.g., caching)
|
|
type ResponseFinalizer interface {
|
|
Finalize()
|
|
}
|