Possibly fix race condition in rate limiting

This commit is contained in:
Neale Pickett 2019-04-30 03:31:16 +00:00
parent 15ee01b69d
commit 03247983bb
3 changed files with 55 additions and 7 deletions

26
contrib/smash Executable file
View File

@ -0,0 +1,26 @@
#! /bin/sh
BASEURL=http://localhost:8080
case "$1" in
a)
URL=$BASEURL/answer
;;
b)
URL=$BASEURL/puzzles.json
;;
*)
echo "Usage: $0 a|b" 1>&2
exit 1
;;
esac
while true; do
curl \
-X POST \
-F "cat=base" \
-F "points=1" \
-F "id=test" \
-F "answer=moo" \
$URL
done

View File

@ -11,6 +11,7 @@ import (
"os"
"path"
"strings"
"sync"
"time"
)
@ -21,12 +22,13 @@ type Instance struct {
ThemeDir string
AttemptInterval time.Duration
categories map[string]*Mothball
update chan bool
jPuzzleList []byte
jPointsLog []byte
nextAttempt map[string]time.Time
mux *http.ServeMux
categories map[string]*Mothball
update chan bool
jPuzzleList []byte
jPointsLog []byte
nextAttempt map[string]time.Time
nextAttemptMutex *sync.RWMutex
mux *http.ServeMux
}
func (ctx *Instance) Initialize() error {
@ -42,6 +44,7 @@ func (ctx *Instance) Initialize() error {
ctx.categories = map[string]*Mothball{}
ctx.update = make(chan bool, 10)
ctx.nextAttempt = map[string]time.Time{}
ctx.nextAttemptMutex = new(sync.RWMutex)
ctx.mux = http.NewServeMux()
ctx.BindHandlers()
@ -129,8 +132,15 @@ func (ctx *Instance) ThemePath(parts ...string) string {
func (ctx *Instance) TooFast(teamId string) bool {
now := time.Now()
ctx.nextAttemptMutex.RLock()
next, _ := ctx.nextAttempt[teamId]
ctx.nextAttemptMutex.RUnlock()
ctx.nextAttemptMutex.Lock()
ctx.nextAttempt[teamId] = now.Add(ctx.AttemptInterval)
ctx.nextAttemptMutex.Unlock()
return now.Before(next)
}
@ -212,7 +222,10 @@ func (ctx *Instance) OpenCategoryFile(category string, parts ...string) (io.Read
}
func (ctx *Instance) ValidTeamId(teamId string) bool {
ctx.nextAttemptMutex.RLock()
_, ok := ctx.nextAttempt[teamId]
ctx.nextAttemptMutex.RUnlock()
return ok
}

View File

@ -186,19 +186,28 @@ func (ctx *Instance) readTeams() {
now := time.Now()
added := 0
for k, _ := range newList {
if _, ok := ctx.nextAttempt[k]; !ok {
ctx.nextAttemptMutex.RLock()
_, ok := ctx.nextAttempt[k]
ctx.nextAttemptMutex.RUnlock()
if !ok {
ctx.nextAttemptMutex.Lock()
ctx.nextAttempt[k] = now
ctx.nextAttemptMutex.Unlock()
added += 1
}
}
// For any removed team IDs, remove them
removed := 0
ctx.nextAttemptMutex.Lock() // XXX: This could be less of a cludgel
for k, _ := range ctx.nextAttempt {
if _, ok := newList[k]; !ok {
delete(ctx.nextAttempt, k)
}
}
ctx.nextAttemptMutex.Unlock()
if (added > 0) || (removed > 0) {
log.Printf("Team IDs updated: %d added, %d removed", added, removed)