Skip to content

Commit

Permalink
Make integer rand min and max configurable (#5)
Browse files Browse the repository at this point in the history
* Add min rand_int_min and rand_int_max + rename placeholder

* Add Validate and Provision w/ error handling

* Adjust readme
  • Loading branch information
steffenbusch authored Oct 26, 2024
1 parent aa3152e commit 5e20efe
Show file tree
Hide file tree
Showing 2 changed files with 96 additions and 29 deletions.
68 changes: 46 additions & 22 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,16 @@ This repository contains the **Extra Placeholders** plugin for the [Caddy](https

This plugin introduces new placeholders that can be used within Caddy configurations:

| Placeholder | Description |
|--------------------------------|---------------------------------------------------|
| `{extra.caddy.version.simple}` | Simple version information of the Caddy server. |
| `{extra.caddy.version.full}` | Full version information of the Caddy server. |
| `{extra.rand.float}` | Random float value between 0.0 and 1.0. |
| `{extra.rand.int.0-100}` | Random integer value between 0 and 100. |
| `{extra.loadavg.1}` | System load average over the last 1 minute. |
| `{extra.loadavg.5}` | System load average over the last 5 minutes. |
| `{extra.loadavg.15}` | System load average over the last 15 minutes. |
| `{extra.hostinfo.uptime}` | System uptime in a human-readable format. |
| Placeholder | Description |
|--------------------------------|-------------------------------------------------------|
| `{extra.caddy.version.simple}` | Simple version information of the Caddy server. |
| `{extra.caddy.version.full}` | Full version information of the Caddy server. |
| `{extra.rand.float}` | Random float value between 0.0 and 1.0. |
| `{extra.rand.int}` | Random integer value between the configured min and max (default is 0 to 100). |
| `{extra.loadavg.1}` | System load average over the last 1 minute. |
| `{extra.loadavg.5}` | System load average over the last 5 minutes. |
| `{extra.loadavg.15}` | System load average over the last 15 minutes. |
| `{extra.hostinfo.uptime}` | System uptime in a human-readable format. |

These placeholders can be used in Caddyfiles to provide dynamic content and system information in responses.

Expand All @@ -36,42 +36,66 @@ To use the extra placeholders, you can add the following directive to your Caddy

```caddyfile
:8080 {
extra_placeholders
extra_placeholders {
rand_int 10 50
}
respond "Caddy Version: {extra.caddy.version.full}, Uptime: {extra.hostinfo.uptime}"
respond "Caddy Version: {extra.caddy.version.full}, Uptime: {extra.hostinfo.uptime}, Random Int: {extra.rand.int}"
}
```

This example demonstrates how to use the additional placeholders provided by this plugin to dynamically insert Caddy version information and system uptime into an HTTP response.
This example demonstrates how to use the additional placeholders provided by this plugin to dynamically insert Caddy version information, system uptime, and a random integer between 10 and 50 into an HTTP response.

### Random Integer Configuration

To configure the range for the `{extra.rand.int}` placeholder, use the `rand_int` subdirective inside the `extra_placeholders` directive. The format is:

```caddyfile
extra_placeholders {
rand_int <min> <max>
}
```

- `<min>`: The minimum value for the random integer (inclusive).
- `<max>`: The maximum value for the random integer (inclusive).

If `rand_int` is not specified, the default values are:

- `RandIntMin = 0`
- `RandIntMax = 100`

This means that `{extra.rand.int}` will default to generating a random integer between 0 and 100 if not explicitly configured.

### Example: Conditional Redirect Based on Random Value

The following example demonstrates how you can use conditional expressions with the random integer placeholder to redirect users to different search engines based on the generated random number:

```caddyfile
:8080 {
extra_placeholders
extra_placeholders {
rand_int 1 100
}
@redirectToGoogle expression `{extra.rand.int.0-100} <= 25`
@redirectToGoogle expression `{extra.rand.int} <= 25`
redir @redirectToGoogle https://www.google.com
@redirectToBing expression `{extra.rand.int.0-100} > 25 && {extra.rand.int.0-100} <= 50`
@redirectToBing expression `{extra.rand.int} > 25 && {extra.rand.int} <= 50`
redir @redirectToBing https://www.bing.com
@redirectToYahoo expression `{extra.rand.int.0-100} > 50 && {extra.rand.int.0-100} <= 75`
@redirectToYahoo expression `{extra.rand.int} > 50 && {extra.rand.int} <= 75`
redir @redirectToYahoo https://www.yahoo.com
@redirectToDuckDuckGo expression `{extra.rand.int.0-100} > 75`
@redirectToDuckDuckGo expression `{extra.rand.int} > 75`
redir @redirectToDuckDuckGo https://www.duckduckgo.com
}
```

In this example:

- If `{extra.rand.int.0-100}` is between 0 and 25, the request is redirected to **Google** ([https://www.google.com](https://www.google.com)).
- If `{extra.rand.int.0-100}` is between 26 and 50, the request is redirected to **Bing** ([https://www.bing.com](https://www.bing.com)).
- If `{extra.rand.int.0-100}` is between 51 and 75, the request is redirected to **Yahoo** ([https://www.yahoo.com](https://www.yahoo.com)).
- If `{extra.rand.int.0-100}` is greater than 75, the request is redirected to **DuckDuckGo** ([https://www.duckduckgo.com](https://www.duckduckgo.com)).
- If `{extra.rand.int}` is between 1 and 25, the request is redirected to **Google** ([https://www.google.com](https://www.google.com)).
- If `{extra.rand.int}` is between 26 and 50, the request is redirected to **Bing** ([https://www.bing.com](https://www.bing.com)).
- If `{extra.rand.int}` is between 51 and 75, the request is redirected to **Yahoo** ([https://www.yahoo.com](https://www.yahoo.com)).
- If `{extra.rand.int}` is greater than 75, the request is redirected to **DuckDuckGo** ([https://www.duckduckgo.com](https://www.duckduckgo.com)).

This example demonstrates how to use the random integer placeholder in combination with conditional expressions to create dynamic redirection rules.

Expand Down
57 changes: 50 additions & 7 deletions extra_placeholders.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,10 @@
package extraplaceholders

import (
"fmt"
"math/rand"
"net/http"
"strconv"
"time"

"github.com/caddyserver/caddy/v2"
Expand All @@ -28,7 +30,10 @@ import (
)

// ExtraPlaceholders represents the structure for the plugin.
type ExtraPlaceholders struct{}
type ExtraPlaceholders struct {
RandIntMin int `json:"rand_int_min,omitempty"`
RandIntMax int `json:"rand_int_max,omitempty"`
}

func init() {
// Register the module with Caddy and specify where in the directive order it should be applied.
Expand All @@ -42,7 +47,7 @@ func init() {
// `{extra.caddy.version.simple}` | Simple version information of the Caddy server.
// `{extra.caddy.version.full}` | Full version information of the Caddy server.
// `{extra.rand.float}` | Random float value between 0.0 and 1.0.
// `{extra.rand.int.0-100}` | Random integer value between 0 and 100.
// `{extra.rand.int}` | Random integer value between the configured min and max (default is 0 to 100).
// `{extra.loadavg.1}` | System load average over the last 1 minute.
// `{extra.loadavg.5}` | System load average over the last 5 minutes.
// `{extra.loadavg.15}` | System load average over the last 15 minutes.
Expand All @@ -56,8 +61,26 @@ func (ExtraPlaceholders) CaddyModule() caddy.ModuleInfo {
}
}

// Provision sets up the module. It is called once the module is instantiated.
func (e *ExtraPlaceholders) Provision(ctx caddy.Context) error {
// Set default values if not configured
if e.RandIntMin == 0 && e.RandIntMax == 0 {
e.RandIntMin = 0
e.RandIntMax = 100
}
return nil
}

// Validate ensures the configuration is correct.
func (e *ExtraPlaceholders) Validate() error {
if e.RandIntMax <= e.RandIntMin {
return fmt.Errorf("invalid configuration: RandIntMax (%d) must be greater than RandIntMin (%d)", e.RandIntMax, e.RandIntMin)
}
return nil
}

// ServeHTTP adds new placeholders and passes the request to the next handler in the chain.
func (ExtraPlaceholders) ServeHTTP(w http.ResponseWriter, r *http.Request, next caddyhttp.Handler) error {
func (e ExtraPlaceholders) ServeHTTP(w http.ResponseWriter, r *http.Request, next caddyhttp.Handler) error {
// Retrieve the replacer from the request context.
repl, ok := r.Context().Value(caddy.ReplacerCtxKey).(*caddy.Replacer)
if !ok {
Expand All @@ -71,7 +94,11 @@ func (ExtraPlaceholders) ServeHTTP(w http.ResponseWriter, r *http.Request, next

// Set placeholders for random float and integer values.
repl.Set("extra.rand.float", rand.Float64())
repl.Set("extra.rand.int.0-100", rand.Intn(101))
if e.RandIntMax > e.RandIntMin {
repl.Set("extra.rand.int", rand.Intn(e.RandIntMax-e.RandIntMin+1)+e.RandIntMin)
} else {
repl.Set("extra.rand.int", rand.Intn(101)) // Default range 0-100 if not properly configured
}

// Set placeholders for system load averages (1, 5, and 15 minutes).
loadAvg, err := load.Avg()
Expand Down Expand Up @@ -103,16 +130,32 @@ func parseCaddyfile(h httpcaddyfile.Helper) (caddyhttp.MiddlewareHandler, error)

// UnmarshalCaddyfile processes the configuration from the Caddyfile.
func (e *ExtraPlaceholders) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
// Consume the directive name and ensure no extra arguments are provided.
// Consume the directive name.
d.Next()
if d.NextArg() {
return d.ArgErr()

for d.NextBlock(0) {
switch d.Val() {
case "rand_int":
args := d.RemainingArgs()
if len(args) != 2 {
return d.ArgErr()
}
min, err1 := strconv.Atoi(args[0])
max, err2 := strconv.Atoi(args[1])
if err1 != nil || err2 != nil {
return d.ArgErr()
}
e.RandIntMin = min
e.RandIntMax = max
}
}
return nil
}

// Interface guards to ensure ExtraPlaceholders implements the necessary interfaces.
var (
_ caddy.Module = (*ExtraPlaceholders)(nil)
_ caddy.Provisioner = (*ExtraPlaceholders)(nil)
_ caddy.Validator = (*ExtraPlaceholders)(nil)
_ caddyhttp.MiddlewareHandler = (*ExtraPlaceholders)(nil)
)

0 comments on commit 5e20efe

Please sign in to comment.