location

package module
v2.0.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 13, 2025 License: MIT Imports: 4 Imported by: 0

README

location

Run Tests codecov Go Report Card GoDoc

A Gin middleware that automatically detects and exposes the server's hostname and scheme by inspecting the incoming http.Request. This is particularly useful when your application runs behind proxies or load balancers, as it intelligently determines the correct public-facing URL.

Features

  • Automatic Detection: Intelligently detects scheme (HTTP/HTTPS) and host from various sources
  • Proxy-Aware: Respects standard proxy headers (X-Forwarded-Proto, X-Forwarded-Host)
  • Flexible Configuration: Support for custom headers and fallback values
  • Base Path Support: Configure base paths for applications running under sub-paths
  • Zero Dependencies: Only depends on Gin framework

How It Works

The middleware examines the request in the following order to determine the scheme and host:

Scheme Detection:

  1. X-Forwarded-Proto header (or custom configured header)
  2. Request URL scheme
  3. TLS connection presence
  4. Protocol string
  5. Configured default scheme (fallback)

Host Detection:

  1. Configured custom host header (e.g., X-Forwarded-Host)
  2. X-Host header
  3. Request Host header
  4. Request URL host
  5. Configured default host (fallback)

Usage

Start using it

Download and install it:

go get github.com/gin-contrib/location/v2

Import it in your code:

import "github.com/gin-contrib/location/v2"
Default Configuration

Use location.Default() for quick setup with sensible defaults:

package main

import (
  "fmt"
  "net/http"

  "github.com/gin-contrib/location/v2"
  "github.com/gin-gonic/gin"
)

func main() {
  router := gin.Default()

  // Configure with default settings:
  // - Scheme: defaults to "http"
  // - Host: defaults to "localhost:8080"
  // - Headers: X-Forwarded-Proto (scheme), X-Forwarded-Host (host)
  router.Use(location.Default())

  router.GET("/", func(c *gin.Context) {
    url := location.Get(c)

    // Access the detected URL components
    fmt.Printf("Scheme: %s\n", url.Scheme) // e.g., "https"
    fmt.Printf("Host: %s\n", url.Host)     // e.g., "example.com"
    fmt.Printf("Path: %s\n", url.Path)     // e.g., ""

    c.String(http.StatusOK, "Full URL: %s", url.String())
  })

  router.Run(":8080")
}
Custom Configuration

Customize the middleware for your specific environment:

package main

import (
  "fmt"
  "net/http"

  "github.com/gin-contrib/location/v2"
  "github.com/gin-gonic/gin"
)

func main() {
  router := gin.Default()

  // Custom configuration for production environment behind a proxy
  router.Use(location.New(location.Config{
    Scheme: "https",                    // Default scheme when not detected
    Host:   "api.example.com",          // Default host when not detected
    Base:   "/v1",                      // Base path for the application
    Headers: location.Headers{
      Scheme: "X-Forwarded-Proto",      // Header for scheme detection
      Host:   "X-Forwarded-Host",       // Header for host detection
    },
  }))

  router.GET("/users", func(c *gin.Context) {
    url := location.Get(c)

    // With Base="/v1", url.Path will be "/v1"
    // Full URL will be: https://api.example.com/v1
    c.JSON(http.StatusOK, gin.H{
      "message": "API endpoint",
      "url":     url.String(),
    })
  })

  router.Run(":8080")
}

Configuration Options

Field Type Description Default
Scheme string Default scheme when not detected "http"
Host string Default host when not detected "localhost:8080"
Base string Base path for the application ""
Headers.Scheme string Header name for scheme detection "X-Forwarded-Proto"
Headers.Host string Header name for host detection "X-Forwarded-Host"

Use Cases

Behind a Reverse Proxy

When running behind nginx, Apache, or other reverse proxies:

router.Use(location.New(location.Config{
  Scheme: "https",
  Host:   "your-domain.com",
  Headers: location.Headers{
    Scheme: "X-Forwarded-Proto",
    Host:   "X-Forwarded-Host",
  },
}))
Kubernetes Ingress

For applications deployed in Kubernetes with an Ingress controller:

router.Use(location.New(location.Config{
  Scheme: "https",
  Host:   "api.myapp.com",
  Base:   "/api",  // If your ingress routes /api to this service
  Headers: location.Headers{
    Scheme: "X-Forwarded-Proto",
    Host:   "X-Forwarded-Host",
  },
}))
Building Absolute URLs

Generate absolute URLs in your responses:

router.GET("/users/:id", func(c *gin.Context) {
  userID := c.Param("id")
  baseURL := location.Get(c)

  // Build absolute URL for the resource
  userURL := fmt.Sprintf("%s/users/%s", baseURL.String(), userID)

  c.JSON(http.StatusOK, gin.H{
    "id":   userID,
    "self": userURL,
  })
})

API Reference

Functions
Default() gin.HandlerFunc

Returns the location middleware with default configuration (HTTP scheme, localhost:8080 host).

New(config Config) gin.HandlerFunc

Returns the location middleware with custom configuration.

Get(c *gin.Context) *url.URL

Retrieves the location information from the Gin context. Returns nil if the middleware is not configured.

Returns: A *url.URL with the following fields:

  • Scheme: The detected or configured scheme (http/https)
  • Host: The detected or configured host (including port if present)
  • Path: The configured base path
Types
Config

Configuration structure for the middleware:

type Config struct {
    Scheme  string   // Default scheme (e.g., "https")
    Host    string   // Default host (e.g., "example.com:443")
    Base    string   // Base path (e.g., "/api/v1")
    Headers Headers  // Custom headers for detection
}
Headers

Header configuration for scheme and host detection:

type Headers struct {
    Scheme string  // Header name for scheme (default: "X-Forwarded-Proto")
    Host   string  // Header name for host (default: "X-Forwarded-Host")
}

Migration from v1

If you're upgrading from v1, simply update your import path:

- import "github.com/gin-contrib/location"
+ import "github.com/gin-contrib/location/v2"

The API remains fully backward compatible. No code changes are required.

Contributing

We welcome contributions! Here's how you can help:

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add some amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

Please ensure:

  • All tests pass (go test -v ./...)
  • Code is formatted (go fmt ./...)
  • Linting passes (golangci-lint run)

License

This project is licensed under the MIT License - see the LICENSE file for details.

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Default

func Default() gin.HandlerFunc

Default returns the location middleware with default configuration.

func Get

func Get(c *gin.Context) *url.URL

Get returns the Location information for the incoming http.Request from the context. If the location is not set a nil value is returned.

func New

func New(config Config) gin.HandlerFunc

New returns the location middleware with user-defined custom configuration.

Types

type Config

type Config struct {
	// Scheme is the default scheme that should be used when it cannot otherwise
	// be ascertained from the incoming http.Request.
	Scheme string

	// Host is the default host that should be used when it cannot otherwise
	// be ascertained from the incoming http.Request.
	Host string

	// Base is the base path that should be used in conjunction with proxy
	// servers that do path re-writing.
	Base string

	// Header used to map schemes and host.
	// May be overridden to allow reading values from custom header fields.
	Headers Headers
}

Config represents all available options for the middleware.

func DefaultConfig

func DefaultConfig() Config

DefaultConfig returns a generic default configuration mapped to localhost.

type Headers

type Headers struct {
	Scheme string
	Host   string
}

Headers represents the header fields used to map schemes and host.

Directories

Path Synopsis
example
custom command
default command

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL