Add support for HTTP rate limiting

Closes #16
This commit is contained in:
2024-12-12 03:10:30 -05:00
parent e8a9435a1b
commit 67d4f8a10a
2 changed files with 148 additions and 24 deletions

View File

@@ -51,6 +51,10 @@ func main () {
0, "http-directory-document",
"The document to use for displaying directory listings over http",
"", cli.ValString)
flagHTTPRateLimit := cli.NewInputFlag (
0, "http-rate-limit",
"Seconds an HTTP client must wait per request",
"", cli.ValString)
flagDirectories := cli.NewFlag (
'd', "directories",
"Serve the contents of directories")
@@ -149,6 +153,9 @@ func main () {
if flagHTTPErrorDocument.Value != "" {
config.Set("http.error-document", flagHTTPErrorDocument.Value)
}
if flagHTTPRateLimit.Value != "" {
config.Set("http.rate-limit", flagHTTPRateLimit.Value)
}
if flagDirectories.Value != "" {
config.Set("http.serve-directories", flagDirectories.Value)
}
@@ -181,17 +188,25 @@ func main () {
// initialize the environment
err = environment.Init(context.Background())
if err != nil { log.Fatal(err) }
if err != nil { log.Fatal("XXX:", err) }
// set up the HTTP handler
rateLimit := 0.0
if rateLimitStr := config.Get("http.rate-limit"); rateLimitStr != "" {
rateLimit, err = strconv.ParseFloat(rateLimitStr, 64)
if err != nil { log.Fatal("XXX bad value for rate limit", err) }
}
handler := stephttp.Handler {
Environment: &environment,
Directories: config.Get("http.serve-directories") == "true",
StepExt: ucontainer.NewSet(slices.Clone(config["http.step-extension"])...),
Index: slices.Clone(config["http.index-file"]),
ErrorDocument: config.Get("http.error-document"),
DirectoryDocument: config.Get("http.directory-document"),
DenyAll: ucontainer.NewSet(configFileName),
Environment: &environment,
Directories: config.Get("http.serve-directories") == "true",
StepExt: ucontainer.NewSet(slices.Clone(config["http.step-extension"])...),
Index: slices.Clone(config["http.index-file"]),
ErrorDocument: config.Get("http.error-document"),
DirectoryDocument: config.Get("http.directory-document"),
DenyAll: ucontainer.NewSet(configFileName),
RateLimit: time.Duration(rateLimit * float64(time.Second)),
TrustXForwardedFor: config.Get("http.trust-x-forwarded-for") == "true",
TrustCFConnectingIP: config.Get("http.trust-cf-connecting-ip") == "true",
}
if len(handler.StepExt) == 0 {
handler.StepExt.Add(".step")
@@ -199,6 +214,8 @@ func main () {
if len(handler.Index) == 0 {
handler.Index = []string { "index.step", "index.html", "index" }
}
err = handler.Init(ctx)
if err != nil { log.Println("XXX", err) }
// set up the HTTP server
httpServer := httpServerRoutine {
@@ -206,10 +223,16 @@ func main () {
Handler: &handler,
}
// set up the trimming routine
trimmer := trimmerRoutine {
HTTPHandler: &handler,
}
// set up the routine manager
manager := routines.Manager {
Routines: []routines.Routine {
&httpServer,
&trimmer,
},
}
@@ -242,6 +265,23 @@ func (this *httpServerRoutine) Run (ctx context.Context) error {
return err
}
type trimmerRoutine struct {
HTTPHandler *stephttp.Handler
}
func (this *trimmerRoutine) Run (ctx context.Context) error {
ticker := time.NewTicker(1 * time.Minute)
defer ticker.Stop()
for {
select {
case <- ticker.C:
this.HTTPHandler.Trim()
case <- ctx.Done():
return ctx.Err()
}
}
}
func logProviders (providers []step.Provider) {
output := "providers: "
x := utf8.RuneCountInString(output)