commit 097bfc03573d1bc7ef07af5fe674ab684742e53e Author: Tommy Parnell Date: Thu Oct 15 00:13:06 2026 -0400 init diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5288997 --- /dev/null +++ b/.gitignore @@ -0,0 +1,13 @@ +# Binaries +*.exe +*.exe~ +*.dll +*.so +*.dylib +redirect-server + +# Test binaries +*.test + +# Output of the go coverage tool +*.out diff --git a/README.md b/README.md new file mode 100644 index 0000000..1534095 --- /dev/null +++ b/README.md @@ -0,0 +1,41 @@ +# VenueAxe Redirect Service + +A lightweight HTTP redirect service written in Go that redirects all incoming traffic to `https://venueaxe.com`. + +## Features +- **Direct Redirect**: All incoming requests redirect directly to `https://venueaxe.com` (paths and query parameters are discarded). +- **Configurable target**: Set via `TARGET_URL` (defaults to `https://venueaxe.com`). +- **Configurable port**: Set via `PORT` (defaults to `8080`). +- **Graceful shutdown**: Handles `SIGINT` / `SIGTERM` signals cleanly. +- **Zero dependencies**: Standard library only (`net/http`). + +## Configuration + +| Environment Variable | Default Value | Description | +|---|---|---| +| `PORT` | `8080` | Port the HTTP server listens on | +| `TARGET_URL` | `https://venueaxe.com` | Destination URL | + +## Running Locally + +```bash +# Run with default settings (port 8080) +go run . + +# Run on a custom port +$env:PORT="3000"; go run . # PowerShell +# or +PORT=3000 go run . # Bash +``` + +## Running Tests + +```bash +go test -v ./... +``` + +## Building Binary + +```bash +go build -o redirect-server.exe . +``` diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..ffa9ac0 --- /dev/null +++ b/go.mod @@ -0,0 +1,3 @@ +module venueaxecomredirect + +go 1.27.2 diff --git a/main.go b/main.go new file mode 100644 index 0000000..ae517b5 --- /dev/null +++ b/main.go @@ -0,0 +1,65 @@ +package main + +import ( + "context" + "log" + "net/http" + "os" + "os/signal" + "syscall" + "time" +) + +const defaultTargetURL = "https://venueaxe.com" + +func getEnv(key, fallback string) string { + if value := os.Getenv(key); value != "" { + return value + } + return fallback +} + +func redirectHandler(targetURL string) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + http.Redirect(w, r, targetURL, http.StatusMovedPermanently) + } +} + +func main() { + port := getEnv("PORT", "8080") + targetURL := getEnv("TARGET_URL", defaultTargetURL) + + mux := http.NewServeMux() + mux.HandleFunc("/", redirectHandler(targetURL)) + + server := &http.Server{ + Addr: ":" + port, + Handler: mux, + ReadTimeout: 5 * time.Second, + WriteTimeout: 10 * time.Second, + IdleTimeout: 120 * time.Second, + } + + // Channel to listen for interrupt signals for graceful shutdown + stop := make(chan os.Signal, 1) + signal.Notify(stop, os.Interrupt, syscall.SIGTERM) + + go func() { + log.Printf("Starting redirect server on :%s -> %s", port, targetURL) + if err := server.ListenAndServe(); err != nil && err != http.ErrServerClosed { + log.Fatalf("HTTP server error: %v\n", err) + } + }() + + <-stop + log.Println("Shutting down server gracefully...") + + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + + if err := server.Shutdown(ctx); err != nil { + log.Fatalf("Server shutdown failed: %+v", err) + } + + log.Println("Server exited") +} diff --git a/main_test.go b/main_test.go new file mode 100644 index 0000000..2cf94cb --- /dev/null +++ b/main_test.go @@ -0,0 +1,56 @@ +package main + +import ( + "net/http" + "net/http/httptest" + "testing" +) + +func TestRedirectHandler(t *testing.T) { + targetURL := "https://venueaxe.com" + + tests := []struct { + name string + requestPath string + }{ + { + name: "Root request", + requestPath: "/", + }, + { + name: "Nested path request", + requestPath: "/venues/123", + }, + { + name: "Query params request", + requestPath: "/search?q=concert&location=nyc", + }, + { + name: "Arbitrary sub-path with query", + requestPath: "/a/b/c/d?token=xyz#hash", + }, + } + + handler := redirectHandler(targetURL) + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + req := httptest.NewRequest(http.MethodGet, tt.requestPath, nil) + w := httptest.NewRecorder() + + handler(w, req) + + resp := w.Result() + defer resp.Body.Close() + + if resp.StatusCode != http.StatusMovedPermanently { + t.Fatalf("expected status %d, got %d", http.StatusMovedPermanently, resp.StatusCode) + } + + location := resp.Header.Get("Location") + if location != targetURL { + t.Errorf("expected redirect location %q, got %q", targetURL, location) + } + }) + } +}