### Server Initialization and Start Source: https://github.com/basecamp/thruster/blob/main/_autodocs/api-reference/server.md Example of creating a new Server instance, starting it, and deferring its stop. ```go config, _ := internal.NewConfig() handler := internal.NewHandler(options) server := internal.NewServer(config, handler) err := server.Start() defer server.Stop() ``` -------------------------------- ### Thruster Quick Start Source: https://github.com/basecamp/thruster/blob/main/_autodocs/README.md This Go code demonstrates the complete implementation of the `thrust` command, including configuration loading, logging setup, and service initialization. ```go package main import ( "fmt" "log/slog" "os" "github.com/basecamp/thruster/internal" ) func main() { // Load configuration from environment variables and command-line args config, err := internal.NewConfig() if err != nil { fmt.Printf("ERROR: %s\n", err) os.Exit(1) } // Set up logging slog.SetDefault(slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{Level: config.LogLevel}))) // Create and run the service service := internal.NewService(config) os.Exit(service.Run()) } ``` -------------------------------- ### Start() Source: https://github.com/basecamp/thruster/blob/main/_autodocs/api-reference/server.md Starts both HTTP and HTTPS listeners. This method is non-blocking and spawns goroutines to accept connections. It handles TLS configuration, ACME challenges, and port binding. ```APIDOC ## Start() ### Description Starts both HTTP and HTTPS listeners (if TLS is enabled) or just the HTTP listener (if not). This method is non-blocking; it spawns goroutines to accept connections. ### Signature ```go func (s *Server) Start() error ``` ### Returns - `error` — `nil` on success, or an error if listener creation fails - Note: Does not return errors from connection processing; those are logged asynchronously ### Behavior **With TLS enabled** (when `config.TLSDomains` is not empty): 1. Creates an ACME certificate manager configured with Let's Encrypt 2. Configures HTTP server on `HttpPort` (default 80) to handle ACME challenges and redirect HTTP to HTTPS 3. Configures HTTPS server on `HttpsPort` (default 443) with TLS enabled and the main handler 4. Attempts to bind both ports 5. Spawns goroutines to serve on both ports 6. Logs successful startup with domain names **Without TLS** (when `config.TLSDomains` is empty): 1. Configures HTTP server on `HttpPort` with the main handler 2. Attempts to bind the port 3. Spawns a goroutine to serve on the port 4. Logs successful startup ### Protocol Support - Always enables HTTP/1.1 and HTTP/2 - Enables h2c (HTTP/2 cleartext) only if `config.H2CEnabled` is true - Sets timeouts from config: `IdleTimeout`, `ReadTimeout`, `WriteTimeout` ### Error Handling - Returns immediately if listener creation fails - Logs all errors with context (listener type, port, error details) - Does not fail fast on port binding errors; returns the error to the caller ### Example ```go server := internal.NewServer(config, handler) if err := server.Start(); err != nil { fmt.Printf("Failed to start server: %v\n", err) return } defer server.Stop() // Server is now listening in the background ``` ``` -------------------------------- ### Example Usage of NewConfig Source: https://github.com/basecamp/thruster/blob/main/_autodocs/api-reference/config.md Demonstrates how to create a new Config instance using NewConfig() and handle potential errors. This example shows basic usage after successful configuration loading. ```go package main import ( "fmt" "github.com/basecamp/thruster/internal" ) func main() { config, err := internal.NewConfig() if err != nil { fmt.Printf("Failed to load configuration: %v\n", err) return } // Use config fmt.Printf("Target port: %d\n", config.TargetPort) fmt.Printf("TLS enabled: %v\n", config.HasTLS()) } ``` -------------------------------- ### Example Usage of NewHandler Source: https://github.com/basecamp/thruster/blob/main/_autodocs/api-reference/handler.md Demonstrates how to create HandlerOptions and use them to construct an http.Handler for an http.Server. This example configures caching, target URL, X-Sendfile, gzip compression, and request logging. ```go config, _ := internal.NewConfig() options := internal.HandlerOptions{ cache: internal.NewMemoryCache(64*1024*1024, 1*1024*1024), targetUrl: &url.URL{Scheme: "http", Host: "localhost:3000"}, xSendfileEnabled: true, gzipCompressionEnabled: true, maxCacheableResponseBody: 1 * 1024 * 1024, maxRequestBody: 0, badGatewayPage: "./public/502.html", forwardHeaders: false, logRequests: true, gzipCompressionDisableOnAuth: false, gzipCompressionJitter: 32, } handler := internal.NewHandler(options) server := &http.Server{ Addr: ":8080", Handler: handler, } server.ListenAndServe() ``` -------------------------------- ### Main Application Entry Point Example Source: https://github.com/basecamp/thruster/blob/main/_autodocs/api-reference/service.md An example of a main function that initializes Thruster's Service, runs it, and exits with the appropriate status code. Handles configuration errors. ```go package main import ( "fmt" "os" "github.com/basecamp/thruster/internal" ) func main() { config, err := internal.NewConfig() if err != nil { fmt.Printf("ERROR: %s\n", err) os.Exit(1) } service := internal.NewService(config) exitCode := service.Run() os.Exit(exitCode) } ``` -------------------------------- ### Example: Using CacheStatus and Caching Response Source: https://github.com/basecamp/thruster/blob/main/_autodocs/api-reference/cacheable-response.md Demonstrates how to use CacheStatus to determine if a response can be cached, and then how to store it using a cache. This example assumes a cache object and handler are available. ```Go cr := internal.NewCacheableResponse(w, 1*1024*1024) handler.ServeHTTP(cr, r) cacheable, expiresAt := cr.CacheStatus() if cacheable { fmt.Printf("Cache until: %v\n", expiresAt) encoded, _ := cr.ToBuffer() cache.Set(key, encoded, expiresAt) } ``` -------------------------------- ### NewService Source: https://github.com/basecamp/thruster/blob/main/_autodocs/api-reference/service.md Creates a new Service instance with the given configuration. This constructor initializes the Service but does not start any processes; use the Run() method to start the service. ```APIDOC ## NewService(config *Config) *Service ### Description Creates a new Service instance with the given configuration. ### Signature ```go func NewService(config *Config) *Service ``` ### Parameters #### Path Parameters (None) #### Query Parameters (None) #### Request Body (None) ### Parameters | Parameter | Type | Required | Default | Description | |-----------|------|----------|---------|-------------| | `config` | `*Config` | Yes | — | The configuration struct created by `NewConfig()` | ### Returns - `*Service` — A new Service instance ready to be run ### Example ```go config, _ := internal.NewConfig() service := internal.NewService(config) exitCode := service.Run() ``` ``` -------------------------------- ### Service Constructor Example Source: https://github.com/basecamp/thruster/blob/main/_autodocs/api-reference/service.md Demonstrates how to create a new Service instance using NewService and then run it. ```go config, _ := internal.NewConfig() service := internal.NewService(config) exitCode := service.Run() ``` -------------------------------- ### Start Server Source: https://github.com/basecamp/thruster/blob/main/_autodocs/api-reference/server.md Starts the HTTP and/or HTTPS listeners. This method is non-blocking and spawns goroutines for connection acceptance. Ensure proper configuration for TLS if needed. Errors during listener creation are returned. ```go server := internal.NewServer(config, handler) if err := server.Start(); err != nil { fmt.Printf("Failed to start server: %v\n", err) return } defer server.Stop() // Server is now listening in the background ``` -------------------------------- ### NewCacheHandler Constructor Example Source: https://github.com/basecamp/thruster/blob/main/_autodocs/api-reference/cache-handler.md Example of creating a new CacheHandler instance. It requires a Cache implementation, a maximum response body size, and the next http.Handler in the chain. ```go cache := internal.NewMemoryCache(64*1024*1024, 1*1024*1024) handler := internal.NewCacheHandler(cache, 1*1024*1024, nextHandler) ``` -------------------------------- ### Install Thruster Gem Globally Source: https://github.com/basecamp/thruster/blob/main/README.md Install the Thruster gem directly using the gem command for global access. ```sh $ gem install thruster ``` -------------------------------- ### Core Components Source: https://github.com/basecamp/thruster/blob/main/_autodocs/MANIFEST.txt Reference for core components including configuration, service, and server setup. ```APIDOC ## NewConfig() ### Description Constructor for creating a new configuration. ### Method NewConfig ### Parameters None ### Response - Returns a Config object. ### Response Example ```json { "example": "Config object" } ``` ## NewService() ### Description Constructor for creating a new service. ### Method NewService ### Parameters None ### Response - Returns a Service object. ### Response Example ```json { "example": "Service object" } ``` ## NewServer() ### Description Constructor for creating a new server. ### Method NewServer ### Parameters None ### Response - Returns a Server object. ### Response Example ```json { "example": "Server object" } ``` ## Config.HasTLS() ### Description Checks if TLS is enabled for the configuration. ### Method HasTLS ### Parameters None ### Response - Returns a boolean indicating if TLS is enabled. ### Response Example ```json { "example": "true or false" } ``` ## Server.Start() ### Description Starts the server. ### Method Start ### Parameters None ### Response None ## Server.Stop() ### Description Stops the server. ### Method Stop ### Parameters None ### Response None ``` -------------------------------- ### NewServer Source: https://github.com/basecamp/thruster/blob/main/_autodocs/api-reference/server.md Creates a new Server instance with the given configuration and request handler. This constructor initializes the server but does not start listening for connections. ```APIDOC ## NewServer ### Description Creates a new Server instance with the given configuration and request handler. This constructor initializes the server but does not start listening for connections. ### Signature func NewServer(config *Config, handler http.Handler) *Server ### Parameters #### Path Parameters (None) #### Query Parameters (None) #### Request Body (None) ### Parameters - **config** (*Config) - Required - The configuration struct controlling server behavior - **handler** (http.Handler) - Required - The handler to process all incoming HTTP requests ### Returns - ***Server** - A new Server instance, not yet listening ### Behavior - Stores the config and handler for use when `Start()` is called - Does not create listeners or bind to ports until `Start()` is called ### Example ```go config, _ := internal.NewConfig() handler := internal.NewHandler(options) server := internal.NewServer(config, handler) err := server.Start() defer server.Stop() ``` ``` -------------------------------- ### NewService Constructor Source: https://github.com/basecamp/thruster/blob/main/_autodocs/api-reference/service.md Creates a new Service instance with the given configuration. It takes ownership of the config and does not perform initialization; use Run() to start the service. ```go func NewService(config *Config) *Service ``` -------------------------------- ### Run Upstream Process and Get Exit Code Source: https://github.com/basecamp/thruster/blob/main/_autodocs/api-reference/upstream-process.md Starts the upstream process, connects its standard streams to the parent process, handles signals, and waits for the process to exit. Use this to launch and manage a child process. ```Go proc := internal.NewUpstreamProcess("bin/rails", "server") exitCode, err := proc.Run() if err != nil { log.Fatal(err) } os.Exit(exitCode) ``` -------------------------------- ### Server Methods Source: https://github.com/basecamp/thruster/blob/main/_autodocs/INDEX.md Methods for the Server type, including starting listeners and graceful shutdown. ```APIDOC ## Server Methods ### `Start()` - **Purpose**: Start listeners. - **Returns**: `error` ### `Stop()` - **Purpose**: Graceful shutdown. ``` -------------------------------- ### Use CacheKey for Caching Operations Source: https://github.com/basecamp/thruster/blob/main/_autodocs/types.md Demonstrates how to obtain a CacheKey and use it with a Cache implementation for setting and getting cached responses. ```Go key := variant.CacheKey() cache.Set(key, response, expiresAt) value, found := cache.Get(key) ``` -------------------------------- ### Example Log Output Source: https://github.com/basecamp/thruster/blob/main/_autodocs/api-reference/logging-handler.md This is an example of the structured JSON output generated by the LoggingHandler for a single HTTP request. It includes various metrics like path, status, duration, method, and client information. ```json {"time":"2024-06-28T10:30:45.123Z","level":"INFO","msg":"Request","path":"/api/users","status":200,"dur":45,"method":"GET","req_content_length":0,"req_content_type":"","resp_content_length":1024,"resp_content_type":"application/json","remote_addr":"192.168.1.100","user_agent":"curl/7.64.1","cache":"miss","query":"","proto":"HTTP/1.1"} ``` -------------------------------- ### JSON Log Format Example Source: https://github.com/basecamp/thruster/blob/main/_autodocs/api-reference/logging-handler.md This is an example of the structured JSON log format produced by the Logging Handler. Parsers typically recognize this format automatically. ```json { "time": "2024-06-28T10:30:45.123Z", "level": "INFO", "msg": "Request", "path": "/api/users", "status": 200, ... } ``` -------------------------------- ### Run Application with Go Source: https://github.com/basecamp/thruster/blob/main/CONTRIBUTING.md Start the Thruster application directly using the `go run` command. This is useful for local development and testing. ```bash go run ./cmd/thrust ``` -------------------------------- ### Instantiate Variant Source: https://github.com/basecamp/thruster/blob/main/_autodocs/api-reference/variant.md Example of creating a new Variant instance using the NewVariant constructor with an http.Request object. ```go variant := internal.NewVariant(r) ``` -------------------------------- ### Service Methods Source: https://github.com/basecamp/thruster/blob/main/_autodocs/INDEX.md Methods available for the Service type, primarily for starting the server and upstream processes. ```APIDOC ## Service Methods ### `Run()` - **Purpose**: Start server and upstream, wait for exit. - **Returns**: `int` - The exit code. ``` -------------------------------- ### Cache HTTP Response with CacheableResponse Source: https://github.com/basecamp/thruster/blob/main/_autodocs/types.md Example demonstrating how to create a CacheableResponse, serve it using a handler, and then cache the serialized response if it's determined to be cacheable. ```go cr := internal.NewCacheableResponse(w, 1*1024*1024) handler.ServeHTTP(cr, r) cacheable, expiresAt := cr.CacheStatus() if cacheable { encoded, _ := cr.ToBuffer() cache.Set(key, encoded, expiresAt) } ``` -------------------------------- ### Basic Thruster Deployment Source: https://github.com/basecamp/thruster/blob/main/_autodocs/README.md Starts Thruster with default HTTPS, HTTP redirection, and proxying to a Rails server. Assumes default cache size and compression settings. ```bash TLS_DOMAIN=myapp.example.com thrust bin/rails server ``` -------------------------------- ### Run() Source: https://github.com/basecamp/thruster/blob/main/_autodocs/api-reference/upstream-process.md Starts the upstream process, connects its standard streams to the current process, handles OS signals for graceful shutdown, and waits for the process to exit, returning its exit code. ```APIDOC ## Run() ### Description Starts the upstream process and waits for it to exit, returning its exit code. This method connects the process's standard input, output, and error streams to the current process's streams, allowing for direct user interaction. It also handles OS signals (like SIGINT and SIGTERM) to gracefully shut down the subprocess and signals the parent service when the process has started. ### Method *Not applicable (Go method)* ### Parameters *Not applicable (Go method)* ### Request Body *Not applicable (Go method)* ### Response - **int**: The exit code of the process (0 for success, non-zero for failure). - **error**: Returns an error if the process fails to start. ### Response Example ```go exitCode, err := proc.Run() if err != nil { log.Fatal(err) } os.Exit(exitCode) ``` ``` -------------------------------- ### Parsing Vary Header Example Source: https://github.com/basecamp/thruster/blob/main/_autodocs/api-reference/variant.md Demonstrates the steps involved in parsing a Vary header, including splitting, trimming, canonicalizing, and sorting header names. Handles empty or missing headers by returning an empty slice. ```text Vary: Accept-Encoding, Accept-Language ↓ (split and trim) ["Accept-Encoding", "Accept-Language"] ↓ (canonicalize and sort) ["Accept-Encoding", "Accept-Language"] (already sorted) ``` -------------------------------- ### NewUpstreamProcess Constructor Source: https://github.com/basecamp/thruster/blob/main/_autodocs/api-reference/upstream-process.md Creates a new UpstreamProcess instance for managing a command and its arguments. The process is not started until Run() is called. ```go func NewUpstreamProcess(name string, arg ...string) *UpstreamProcess ``` ```go proc := internal.NewUpstreamProcess("bin/rails", "server") ``` -------------------------------- ### Run Source: https://github.com/basecamp/thruster/blob/main/_autodocs/api-reference/service.md Starts the Service, including the HTTP/HTTPS server and upstream application process. This method blocks until the upstream process exits, then performs cleanup and returns its exit code. ```APIDOC ## Run() int ### Description Starts the Service, including the HTTP/HTTPS server and upstream application process. This method blocks until the upstream process exits, then performs cleanup and returns its exit code. ### Signature ```go func (s *Service) Run() int ``` ### Parameters #### Path Parameters (None) #### Query Parameters (None) #### Request Body (None) ### Returns - `int` — The exit code of the upstream process, or `1` if the server failed to start ### Behavior 1. Creates a [MemoryCache](./memory-cache.md) based on config settings 2. Constructs the target URL as `http://localhost:{TargetPort}` 3. Builds the complete request handler chain using [NewHandler](./handler.md) 4. Creates and starts the [Server](./server.md) with the handler 5. Sets the `PORT` environment variable for the upstream process 6. Starts the upstream application process 7. Waits for the upstream process to exit 8. Gracefully shuts down the server (5 second timeout) 9. Returns the upstream process's exit code ### Return Values - Returns `1` if the server fails to start - Returns the upstream process exit code otherwise (0 for success, non-zero for failure) ### Error Handling - If server startup fails, logs an error and returns `1` immediately - If the upstream process fails to start, logs an error with command details and returns `1` - Graceful shutdown has a 5-second timeout; does not propagate errors from shutdown ### Example ```go package main import ( "fmt" "os" "github.com/basecamp/thruster/internal" ) func main() { config, err := internal.NewConfig() if err != nil { fmt.Printf("ERROR: %s\n", err) os.Exit(1) } service := internal.NewService(config) exitCode := service.Run() os.Exit(exitCode) } ``` ``` -------------------------------- ### Enable Debug Logging Source: https://github.com/basecamp/thruster/blob/main/_autodocs/api-reference/logging-handler.md Enables debug-level logs by setting the DEBUG environment variable to 1 before starting the server. This includes additional diagnostic information. ```bash DEBUG=1 thrust bin/rails server ``` -------------------------------- ### Set Maximum Request Body Size Source: https://github.com/basecamp/thruster/blob/main/_autodocs/README.md Configure the maximum allowed request body size using the MAX_REQUEST_BODY environment variable. This example sets it to 10MB. ```bash MAX_REQUEST_BODY=$((10*1024*1024)) thrust bin/rails server ``` -------------------------------- ### Initialize and Use CacheHandler Source: https://github.com/basecamp/thruster/blob/main/_autodocs/types.md Shows how to instantiate a MemoryCache and use it with a CacheHandler, passing the cache instance and other configuration to the handler. ```Go var cache internal.Cache = internal.NewMemoryCache(64*1024*1024, 1*1024*1024) handler := internal.NewCacheHandler(cache, 1*1024*1024, nextHandler) ``` -------------------------------- ### NewUpstreamProcess Source: https://github.com/basecamp/thruster/blob/main/_autodocs/api-reference/upstream-process.md Creates a new UpstreamProcess instance to manage an upstream application server. This constructor initializes the process manager but does not start the process itself. The process is started when the Run() method is invoked. ```APIDOC ## NewUpstreamProcess ### Description Creates a new UpstreamProcess with the given command and arguments. This function initializes the process manager but does not spawn the process until Run() is called. ### Signature ```go func NewUpstreamProcess(name string, arg ...string) *UpstreamProcess ``` ### Parameters #### Path Parameters - **name** (string) - Required - The command to execute (e.g., `bin/rails`) - **arg** (string) - Optional - Command-line arguments (e.g., `server`) ### Returns - `*UpstreamProcess` - A new process manager, not yet started ### Example ```go proc := internal.NewUpstreamProcess("bin/rails", "server") ``` ``` -------------------------------- ### Initialize Logging Configuration Source: https://github.com/basecamp/thruster/blob/main/_autodocs/api-reference/logging-handler.md Sets up the initial logging configuration, defaulting to Info level and enabling request logging. It checks for a DEBUG environment variable to enable debug-level logs. ```go config := &Config{ LogLevel: slog.LevelInfo, // Default LogRequests: true, // Default } if getEnvBool("DEBUG", false) { config.LogLevel = slog.LevelDebug } ``` -------------------------------- ### Command Line Entry Point Source: https://github.com/basecamp/thruster/blob/main/_autodocs/INDEX.md This Go code snippet shows the typical command-line entry point for the Thruster service. It initializes the configuration and service, then runs the service. ```go config, _ := internal.NewConfig() service := internal.NewService(config) os.Exit(service.Run()) ``` -------------------------------- ### HasTLS() Source: https://github.com/basecamp/thruster/blob/main/_autodocs/api-reference/config.md Checks if TLS/HTTPS is enabled for the current configuration. This method returns true if at least one domain is specified for TLS, indicating that both HTTP and HTTPS servers will be started, with HTTP traffic redirected to HTTPS. If false, only the HTTP server is started. ```APIDOC ## HasTLS() ### Description Returns whether TLS/HTTPS is enabled for this configuration. This is determined by checking if the `TLSDomains` field is non-empty. ### Method `HasTLS()` ### Parameters None ### Returns - `bool` — `true` if `TLSDomains` is non-empty, `false` otherwise. ### Behavior - Returns `true` only if the `TLSDomains` slice is non-empty. - When `true`, both HTTP and HTTPS servers are started and HTTP traffic is redirected to HTTPS. - When `false`, only the HTTP server is started. ### Example ```go config, _ := internal.NewConfig() if config.HasTLS() { fmt.Println("TLS is enabled") } ``` ``` -------------------------------- ### Server Constructor Signature Source: https://github.com/basecamp/thruster/blob/main/_autodocs/api-reference/server.md Provides the function signature for creating a new Server instance. ```go func NewServer(config *Config, handler http.Handler) *Server ``` -------------------------------- ### UpstreamProcess Methods Source: https://github.com/basecamp/thruster/blob/main/_autodocs/INDEX.md Methods for managing subprocesses, including starting, waiting, and signaling. ```APIDOC ## UpstreamProcess Methods ### `Run()` - **Purpose**: Start and wait for process. - **Returns**: `(int, error)` - The exit code and any error. ### `Signal(sig)` - **Purpose**: Send signal to process. - **Parameters**: - `sig` (os.Signal) - The signal to send. - **Returns**: `error` ``` -------------------------------- ### Build Cross-Platform Binaries with Make Source: https://github.com/basecamp/thruster/blob/main/CONTRIBUTING.md Generate binaries for all supported architectures and operating systems using the `make dist` command. These binaries will be placed in the `dist/` directory. ```bash make dist ``` -------------------------------- ### Get(key CacheKey) ([]byte, bool) Source: https://github.com/basecamp/thruster/blob/main/_autodocs/api-reference/memory-cache.md Retrieves a value from the cache if it exists and has not expired. ```APIDOC ## Get(key CacheKey) ([]byte, bool) ### Description Retrieves a value from the cache if it exists and has not expired. ### Method Signature ```go func (c *MemoryCache) Get(key CacheKey) ([]byte, bool) ``` ### Parameters #### Path Parameters - **key** (CacheKey) - Yes - Unique identifier for the cached response to retrieve ### Returns - **[]byte** — The cached response content, or `nil` if not found or expired - **bool** — `true` if the value was found and valid, `false` if not found or expired ### Behavior 1. Acquires a read lock 2. Checks if the key exists in the cache 3. If found, checks if the item has expired - If expired: deletes the item and returns `(nil, false)` - If not expired: updates the `lastAccessedAt` timestamp and returns the value 4. If not found: returns `(nil, false)` ### Thread Safety - Safe to call from multiple goroutines; uses a mutex to serialize access - The `lastAccessedAt` timestamp is updated on each hit to support LRU-like eviction ### Example ```go cache := internal.NewMemoryCache(1024*1024, 512*1024) // ... store something ... key := internal.CacheKey(12345) cache.Set(key, []byte("response"), time.Now().Add(time.Hour)) // Retrieve it value, found := cache.Get(key) if found { fmt.Printf("Cache hit: %s\n", string(value)) } else { fmt.Println("Cache miss") } ``` ``` -------------------------------- ### Build Application for Current Environment with Make Source: https://github.com/basecamp/thruster/blob/main/CONTRIBUTING.md Compile the Thruster application for the current operating system and architecture using the Makefile. The resulting binary will be placed in the `bin/` directory. ```bash make build ``` -------------------------------- ### Run All Tests with Make Source: https://github.com/basecamp/thruster/blob/main/CONTRIBUTING.md Execute the entire test suite using the provided Makefile. This is a convenient way to ensure all tests pass before making changes. ```bash make test ``` -------------------------------- ### Get Response Headers Source: https://github.com/basecamp/thruster/blob/main/_autodocs/api-reference/cacheable-response.md Retrieves the mutable response header map. This map can be modified before WriteHeader is called. ```Go func (c *CacheableResponse) Header() http.Header ``` -------------------------------- ### Initialize SendfileHandler Source: https://github.com/basecamp/thruster/blob/main/_autodocs/api-reference/sendfile-handler.md Creates a new SendfileHandler instance. Set 'enabled' to true to activate X-Sendfile processing. 'next' is the subsequent http.Handler in the chain. ```go handler := internal.NewSendfileHandler(true, nextHandler) ``` -------------------------------- ### Disable Request Logging Source: https://github.com/basecamp/thruster/blob/main/_autodocs/api-reference/logging-handler.md Disables request logging by setting the LOG_REQUESTS environment variable to 0 before starting the server. ```bash LOG_REQUESTS=0 thrust bin/rails server ``` -------------------------------- ### Cache Interface Source: https://github.com/basecamp/thruster/blob/main/_autodocs/types.md The Cache interface defines the contract for cache implementations, providing methods to get and set cached responses. ```APIDOC ## Cache Interface ### Description The interface that cache implementations must satisfy. Defines the core operations for storing and retrieving cached responses. ### Methods - `Get(key CacheKey) ([]byte, bool)` — Retrieves a cached response by key; returns (nil, false) if not found or expired - `Set(key CacheKey, value []byte, expiresAt time.Time)` — Stores a response in the cache with an expiration time ### Implementations - `MemoryCache` — In-memory cache with LRU-like eviction ### Example ```go var cache internal.Cache = internal.NewMemoryCache(64*1024*1024, 1*1024*1024) handler := internal.NewCacheHandler(cache, 1*1024*1024, nextHandler) ``` ``` -------------------------------- ### Create New LoggingHandler Source: https://github.com/basecamp/thruster/blob/main/_autodocs/api-reference/logging-handler.md Instantiates a new LoggingHandler. Use this to wrap your existing http.Handler with logging capabilities. Requires a logger instance and the next handler in the chain. ```go handler := internal.NewLoggingHandler(slog.Default(), nextHandler) ``` -------------------------------- ### Low Security Compression Handler Source: https://github.com/basecamp/thruster/blob/main/_autodocs/api-reference/compression-handler.md Configure CompressionHandler with default 32-byte jitter and no special guard for low security requirements. ```go handler := internal.NewCompressionHandler(32, false, nextHandler) // Compression with default 32-byte jitter, no special guard ``` -------------------------------- ### Create New CompressionHandler Source: https://github.com/basecamp/thruster/blob/main/_autodocs/api-reference/compression-handler.md Instantiates a new CompressionHandler. Use this to add gzip compression to your HTTP responses. Configure jitter for response size padding and optionally enable authentication guards to prevent BREACH attacks. ```go func NewCompressionHandler(jitter int, disableOnAuth bool, next http.Handler) http.Handler { // ... implementation details ... } ``` ```go handler := internal.NewCompressionHandler(32, false, nextHandler) // Compression with 32 bytes of jitter, no authentication guard ``` -------------------------------- ### UpstreamProcess Struct Definition Source: https://github.com/basecamp/thruster/blob/main/_autodocs/api-reference/upstream-process.md Defines the UpstreamProcess struct, which manages an upstream application server process. It includes a channel to signal process start and the underlying exec.Cmd. ```go type UpstreamProcess struct { Started chan struct{} cmd *exec.Cmd } ``` -------------------------------- ### ServeHTTP Method Implementation Source: https://github.com/basecamp/thruster/blob/main/_autodocs/api-reference/cache-handler.md This snippet shows the typical creation and usage of a CacheHandler. It's usually instantiated via NewHandler and not called directly. The handler processes HTTP requests, serving from cache when possible. ```go func (h *CacheHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { // ... implementation details ... } ``` ```go // This is typically created by NewHandler and not called directly handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { cache := internal.NewMemoryCache(64*1024*1024, 1*1024*1024) cacheHandler := internal.NewCacheHandler(cache, 1*1024*1024, backendHandler) cacheHandler.ServeHTTP(w, r) }) ``` -------------------------------- ### Create New CompressionGuardHandler Source: https://github.com/basecamp/thruster/blob/main/_autodocs/api-reference/compression-guard-handler.md Instantiates a new CompressionGuardHandler. This handler should wrap the next handler in your HTTP chain, typically the CompressionHandler, to protect sensitive traffic from compression. ```go handler := internal.NewCompressionGuardHandler(nextHandler) ``` -------------------------------- ### Medium Security Compression Handler Source: https://github.com/basecamp/thruster/blob/main/_autodocs/api-reference/compression-handler.md Configure CompressionHandler with increased 64-byte jitter for medium security requirements. ```go handler := internal.NewCompressionHandler(64, false, nextHandler) // Compression with increased 64-byte jitter ``` -------------------------------- ### Get Variant Headers Source: https://github.com/basecamp/thruster/blob/main/_autodocs/api-reference/variant.md Returns a header map containing request header values for headers specified in the Vary header. This map is stored with cached responses for variant matching. ```go variant := internal.NewVariant(r) // Request has Accept-Encoding: gzip variant.SetResponseHeader(responseHeaders) // Vary: Accept-Encoding variantHeader := variant.VariantHeader() // variantHeader = {Accept-Encoding: gzip} ``` -------------------------------- ### Run Individual Go Test Source: https://github.com/basecamp/thruster/blob/main/CONTRIBUTING.md Execute a specific Go test case using the `go test` command. Use the `-v` flag for verbose output and `-run` with a regular expression to target a specific test function. ```bash go test -v -run ^TestVariantMatches_multiple_headers$ ./... ``` -------------------------------- ### Get Value from Memory Cache Source: https://github.com/basecamp/thruster/blob/main/_autodocs/api-reference/memory-cache.md Retrieves a byte slice from the cache if it exists and has not expired. Returns a boolean indicating success. This operation updates the last accessed time for LRU-like eviction and is safe for concurrent use. ```go cache := internal.NewMemoryCache(1024*1024, 512*1024) // ... store something ... key := internal.CacheKey(12345) cache.Set(key, []byte("response"), time.Now().Add(time.Hour)) // Retrieve it value, found := cache.Get(key) if found { fmt.Printf("Cache hit: %s\n", string(value)) } else { fmt.Println("Cache miss") } ``` -------------------------------- ### Cache Key Computation with Vary Header Source: https://github.com/basecamp/thruster/blob/main/_autodocs/api-reference/variant.md Illustrates how a cache key is computed for a typical request, incorporating the method, path, query, host, and relevant headers specified in the Vary header. Shows how different header values lead to separate cache entries. ```text GET /api/users?search=foo HTTP/1.1 Host: api.example.com Accept-Encoding: gzip Accept-Language: en-US Response has: Vary: Accept-Encoding The cache key is computed from: - Method: "GET" - Path: "/api/users" - Query: "search=foo" - Host: "api.example.com" - Accept-Encoding=gzip (from Vary header) A subsequent request with the same path but Accept-Encoding: deflate would produce a different cache key and be cached separately. ``` -------------------------------- ### High Security Compression Handler Source: https://github.com/basecamp/thruster/blob/main/_autodocs/api-reference/compression-handler.md Configure CompressionHandler with a guard for high security requirements, optionally with no jitter. ```go handler := internal.NewCompressionHandler(32, true, nextHandler) // Or even: handler := internal.NewCompressionHandler(0, true, nextHandler) // Compression with guard, optionally no jitter (guard is primary) ``` -------------------------------- ### Create a New ProxyHandler Source: https://github.com/basecamp/thruster/blob/main/_autodocs/api-reference/proxy-handler.md Instantiates a new ProxyHandler to forward requests to a specified target URL. Configure whether to forward client headers and provide a custom HTML page for 502 errors. ```Go targetUrl := &url.URL{Scheme: "http", Host: "localhost:3000"} handler := internal.NewProxyHandler(targetUrl, "./public/502.html", false) ``` -------------------------------- ### ServeFile Functionality Source: https://github.com/basecamp/thruster/blob/main/_autodocs/api-reference/sendfile-handler.md This function handles file serving when an X-Sendfile header is detected. It sets the Content-Length and uses http.ServeFile to stream the file, managing Content-Type, range requests, and OS sendfile. ```Go func (w *sendfileWriter) serveFile(filename string) { w.log("X-Sendfile is sending file %s", filename) w.setContentLength(filename) http.ServeFile(w.ResponseWriter, w.Request, filename) } ``` -------------------------------- ### Request Flow with Compression Guard Source: https://github.com/basecamp/thruster/blob/main/_autodocs/api-reference/compression-guard-handler.md Illustrates the request flow when the CompressionGuardHandler is active and a Cookie header is present, leading to compression being skipped. ```text Request Flow: Request with Cookie header ↓ CompressionGuardHandler sets X-No-Compression: 1 ↓ CompressionHandler checks X-No-Compression ↓ Compression is skipped ↓ Client receives uncompressed response ``` -------------------------------- ### Push Gems to Registry Source: https://github.com/basecamp/thruster/blob/main/CONTRIBUTING.md Iterate through all generated `.gem` files in the `pkg/` directory and push them to the gem registry. This command is part of the release process. ```bash for g in pkg/*.gem ; do gem push $g ; done ``` -------------------------------- ### HTTP Middleware Source: https://github.com/basecamp/thruster/blob/main/_autodocs/MANIFEST.txt Documentation for various HTTP middleware handlers. ```APIDOC ## NewProxyHandler() ### Description Constructor for creating a new proxy handler. ### Method NewProxyHandler ### Parameters None ### Response - Returns a ProxyHandler object. ### Response Example ```json { "example": "ProxyHandler object" } ``` ## NewCompressionHandler() ### Description Constructor for creating a new compression handler. ### Method NewCompressionHandler ### Parameters None ### Response - Returns a CompressionHandler object. ### Response Example ```json { "example": "CompressionHandler object" } ``` ## NewCompressionGuardHandler() ### Description Constructor for creating a new compression guard handler. ### Method NewCompressionGuardHandler ### Parameters None ### Response - Returns a CompressionGuardHandler object. ### Response Example ```json { "example": "CompressionGuardHandler object" } ``` ## NewSendfileHandler() ### Description Constructor for creating a new sendfile handler. ### Method NewSendfileHandler ### Parameters None ### Response - Returns a SendfileHandler object. ### Response Example ```json { "example": "SendfileHandler object" } ``` ## SendfileHandler.ServeHTTP() ### Description Handles incoming HTTP requests for serving files. ### Method ServeHTTP ### Parameters None ### Response None ## NewLoggingHandler() ### Description Constructor for creating a new logging handler. ### Method NewLoggingHandler ### Parameters None ### Response - Returns a LoggingHandler object. ### Response Example ```json { "example": "LoggingHandler object" } ``` ## LoggingHandler.ServeHTTP() ### Description Handles incoming HTTP requests for logging. ### Method ServeHTTP ### Parameters None ### Response None ``` -------------------------------- ### Custom Thruster Deployment Configuration Source: https://github.com/basecamp/thruster/blob/main/_autodocs/README.md Deploys Thruster with custom domain names, cache size, max cache item size, gzip compression behavior, and HTTP idle timeout settings. ```bash TLS_DOMAIN=app.com,www.app.com \ CACHE_SIZE=$((128*1024*1024)) \ MAX_CACHE_ITEM_SIZE=$((2*1024*1024)) \ GZIP_COMPRESSION_DISABLE_ON_AUTH=true \ HTTP_IDLE_TIMEOUT=120 \ thrust bin/rails server ``` -------------------------------- ### NewHandler Constructor Signature Source: https://github.com/basecamp/thruster/blob/main/_autodocs/api-reference/handler.md Constructs and returns the complete request handler chain based on the provided options. The chain is built from innermost (proxy) to outermost (logging). ```go func NewHandler(options HandlerOptions) http.Handler ``` -------------------------------- ### Run Method Signature Source: https://github.com/basecamp/thruster/blob/main/_autodocs/api-reference/service.md The signature for the Run method of the Service type. ```go func (s *Service) Run() int ```