Skip to content

Instantly share code, notes, and snippets.

@jrwren
Created February 28, 2022 18:08
Show Gist options
  • Save jrwren/2c1329b9920eef5b7b398164b3f74875 to your computer and use it in GitHub Desktop.
Save jrwren/2c1329b9920eef5b7b398164b3f74875 to your computer and use it in GitHub Desktop.
a slow server useful for testing
package main
import (
"errors"
"io"
"log"
"net/http"
"os"
"strconv"
"time"
)
func main() {
r := http.NewServeMux()
r.HandleFunc("/", slow)
log.Fatal(http.ListenAndServe(":9999",r))
}
func slow(w http.ResponseWriter, r *http.Request) {
// The slow return of this function is to take 5 minutes.
// We shall return ~1MB total. and use american english dictionary for fun.
f, err := os.Open("/usr/share/dict/words")
if err != nil {
log.Print("couldn't open /usr/share/dict/words")
return
}
defer f.Close()
t := 5 * time.Minute
d := r.Form.Get("duration")
if d != `` {
if t2, err := time.ParseDuration(d); err == nil {
t = t2
} else {
log.Print("couldn't parse query parameter", d, err)
}
}
delay := 2 * time.Second
st, err := f.Stat()
if err != nil {
log.Print("couldn't stat /usr/share/dict/words")
return
}
src, dst := f, w
sz := int(st.Size())
chunk := sz / int(t/delay)
log.Printf("/slow writing %d every %s for %s", chunk, delay, t)
w.Header().Set("content-length", strconv.Itoa(sz))
buf := make([]byte, chunk)
// lifted from io:
for {
nr, er := src.Read(buf)
if nr > 0 {
nw, ew := dst.Write(buf[0:nr])
if nw < 0 || nr < nw {
nw = 0
if ew == nil {
ew = errInvalidWrite
}
}
time.Sleep(delay)
if ew != nil {
err = ew
break
}
if nr != nw {
err = io.ErrShortWrite
break
}
}
if er != nil {
if er != io.EOF {
err = er
}
break
}
}
if err != nil {
log.Printf("/slow error writing %s", err)
}
}
// errInvalidWrite means that a write returned an impossible count.
var errInvalidWrite = errors.New("invalid write result")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment