This commit is contained in:
2026-10-15 00:13:06 -04:00
commit 097bfc0357
5 changed files with 178 additions and 0 deletions

13
.gitignore vendored Normal file
View File

@@ -0,0 +1,13 @@
# Binaries
*.exe
*.exe~
*.dll
*.so
*.dylib
redirect-server
# Test binaries
*.test
# Output of the go coverage tool
*.out

41
README.md Normal file
View File

@@ -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 .
```

3
go.mod Normal file
View File

@@ -0,0 +1,3 @@
module venueaxecomredirect
go 1.27.2

65
main.go Normal file
View File

@@ -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")
}

56
main_test.go Normal file
View File

@@ -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)
}
})
}
}