Skip to content
Snippets Groups Projects
Commit 42347087 authored by Will McCutchen's avatar Will McCutchen
Browse files

Simplify configuration

parent d5ff1777
Branches
Tags
No related merge requests found
...@@ -457,7 +457,7 @@ func (h *HTTPBin) Delay(w http.ResponseWriter, r *http.Request) { ...@@ -457,7 +457,7 @@ func (h *HTTPBin) Delay(w http.ResponseWriter, r *http.Request) {
return return
} }
delay, err := parseBoundedDuration(parts[2], 0, h.options.MaxResponseTime) delay, err := parseBoundedDuration(parts[2], 0, h.options.MaxDuration)
if err != nil { if err != nil {
http.Error(w, "Invalid duration", http.StatusBadRequest) http.Error(w, "Invalid duration", http.StatusBadRequest)
return return
...@@ -481,7 +481,7 @@ func (h *HTTPBin) Drip(w http.ResponseWriter, r *http.Request) { ...@@ -481,7 +481,7 @@ func (h *HTTPBin) Drip(w http.ResponseWriter, r *http.Request) {
userDuration := q.Get("duration") userDuration := q.Get("duration")
if userDuration != "" { if userDuration != "" {
duration, err = parseBoundedDuration(userDuration, 0, h.options.MaxResponseTime) duration, err = parseBoundedDuration(userDuration, 0, h.options.MaxDuration)
if err != nil { if err != nil {
http.Error(w, "Invalid duration", http.StatusBadRequest) http.Error(w, "Invalid duration", http.StatusBadRequest)
return return
...@@ -490,7 +490,7 @@ func (h *HTTPBin) Drip(w http.ResponseWriter, r *http.Request) { ...@@ -490,7 +490,7 @@ func (h *HTTPBin) Drip(w http.ResponseWriter, r *http.Request) {
userDelay := q.Get("delay") userDelay := q.Get("delay")
if userDelay != "" { if userDelay != "" {
delay, err = parseBoundedDuration(userDelay, 0, h.options.MaxResponseTime) delay, err = parseBoundedDuration(userDelay, 0, h.options.MaxDuration)
if err != nil { if err != nil {
http.Error(w, "Invalid delay", http.StatusBadRequest) http.Error(w, "Invalid delay", http.StatusBadRequest)
return return
...@@ -500,7 +500,7 @@ func (h *HTTPBin) Drip(w http.ResponseWriter, r *http.Request) { ...@@ -500,7 +500,7 @@ func (h *HTTPBin) Drip(w http.ResponseWriter, r *http.Request) {
userNumBytes := q.Get("numbytes") userNumBytes := q.Get("numbytes")
if userNumBytes != "" { if userNumBytes != "" {
numbytes, err = strconv.ParseInt(userNumBytes, 10, 64) numbytes, err = strconv.ParseInt(userNumBytes, 10, 64)
if err != nil || numbytes <= 0 || numbytes > h.options.MaxResponseSize { if err != nil || numbytes <= 0 || numbytes > h.options.MaxMemory {
http.Error(w, "Invalid numbytes", http.StatusBadRequest) http.Error(w, "Invalid numbytes", http.StatusBadRequest)
return return
} }
...@@ -515,7 +515,7 @@ func (h *HTTPBin) Drip(w http.ResponseWriter, r *http.Request) { ...@@ -515,7 +515,7 @@ func (h *HTTPBin) Drip(w http.ResponseWriter, r *http.Request) {
} }
} }
if duration+delay > h.options.MaxResponseTime { if duration+delay > h.options.MaxDuration {
http.Error(w, "Too much time", http.StatusBadRequest) http.Error(w, "Too much time", http.StatusBadRequest)
return return
} }
......
...@@ -20,13 +20,11 @@ import ( ...@@ -20,13 +20,11 @@ import (
) )
const maxMemory int64 = 1024 * 1024 const maxMemory int64 = 1024 * 1024
const maxResponseSize = 1024 const maxDuration time.Duration = 1 * time.Second
const maxResponseTime time.Duration = 1 * time.Second
var app = NewHTTPBin(&Options{ var app = NewHTTPBinWithOptions(&Options{
MaxMemory: maxMemory, MaxMemory: maxMemory,
MaxResponseSize: maxResponseSize, MaxDuration: maxDuration,
MaxResponseTime: maxResponseTime,
}) })
var handler = app.Handler() var handler = app.Handler()
...@@ -60,13 +58,6 @@ func assertBodyEquals(t *testing.T, w *httptest.ResponseRecorder, want string) { ...@@ -60,13 +58,6 @@ func assertBodyEquals(t *testing.T, w *httptest.ResponseRecorder, want string) {
} }
} }
func TestNewHTTPBin__NilOptions(t *testing.T) {
h := NewHTTPBin(nil)
if h.options.MaxMemory != 0 {
t.Fatalf("expected default MaxMemory == 0, got %#v", h.options.MaxMemory)
}
}
func TestIndex(t *testing.T) { func TestIndex(t *testing.T) {
r, _ := http.NewRequest("GET", "/", nil) r, _ := http.NewRequest("GET", "/", nil)
w := httptest.NewRecorder() w := httptest.NewRecorder()
...@@ -1341,7 +1332,7 @@ func TestDelay(t *testing.T) { ...@@ -1341,7 +1332,7 @@ func TestDelay(t *testing.T) {
// as are floating point seconds // as are floating point seconds
{"/delay/0", 0}, {"/delay/0", 0},
{"/delay/0.5", 500 * time.Millisecond}, {"/delay/0.5", 500 * time.Millisecond},
{"/delay/1", maxResponseTime}, {"/delay/1", maxDuration},
} }
for _, test := range okTests { for _, test := range okTests {
t.Run("ok"+test.url, func(t *testing.T) { t.Run("ok"+test.url, func(t *testing.T) {
...@@ -1418,7 +1409,7 @@ func TestDrip(t *testing.T) { ...@@ -1418,7 +1409,7 @@ func TestDrip(t *testing.T) {
{&url.Values{"numbytes": {"1"}}, 0, 1, http.StatusOK}, {&url.Values{"numbytes": {"1"}}, 0, 1, http.StatusOK},
{&url.Values{"numbytes": {"101"}}, 0, 101, http.StatusOK}, {&url.Values{"numbytes": {"101"}}, 0, 101, http.StatusOK},
{&url.Values{"numbytes": {fmt.Sprintf("%d", maxResponseSize)}}, 0, maxResponseSize, http.StatusOK}, {&url.Values{"numbytes": {fmt.Sprintf("%d", maxMemory)}}, 0, int(maxMemory), http.StatusOK},
{&url.Values{"code": {"100"}}, 0, 10, 100}, {&url.Values{"code": {"100"}}, 0, 10, 100},
{&url.Values{"code": {"404"}}, 0, 10, 404}, {&url.Values{"code": {"404"}}, 0, 10, 404},
...@@ -1472,7 +1463,7 @@ func TestDrip(t *testing.T) { ...@@ -1472,7 +1463,7 @@ func TestDrip(t *testing.T) {
{&url.Values{"numbytes": {"0"}}, http.StatusBadRequest}, {&url.Values{"numbytes": {"0"}}, http.StatusBadRequest},
{&url.Values{"numbytes": {"-1"}}, http.StatusBadRequest}, {&url.Values{"numbytes": {"-1"}}, http.StatusBadRequest},
{&url.Values{"numbytes": {"0xff"}}, http.StatusBadRequest}, {&url.Values{"numbytes": {"0xff"}}, http.StatusBadRequest},
{&url.Values{"numbytes": {fmt.Sprintf("%d", maxResponseSize+1)}}, http.StatusBadRequest}, {&url.Values{"numbytes": {fmt.Sprintf("%d", maxMemory+1)}}, http.StatusBadRequest},
{&url.Values{"code": {"foo"}}, http.StatusBadRequest}, {&url.Values{"code": {"foo"}}, http.StatusBadRequest},
{&url.Values{"code": {"-1"}}, http.StatusBadRequest}, {&url.Values{"code": {"-1"}}, http.StatusBadRequest},
......
...@@ -6,6 +6,12 @@ import ( ...@@ -6,6 +6,12 @@ import (
"time" "time"
) )
// Default configuration values
const (
DefaultMaxMemory int64 = 1024 * 1024
DefaultMaxDuration = 10 * time.Second
)
const jsonContentType = "application/json; encoding=utf-8" const jsonContentType = "application/json; encoding=utf-8"
const htmlContentType = "text/html; charset=utf-8" const htmlContentType = "text/html; charset=utf-8"
...@@ -72,9 +78,13 @@ type streamResponse struct { ...@@ -72,9 +78,13 @@ type streamResponse struct {
// Options are used to configure HTTPBin // Options are used to configure HTTPBin
type Options struct { type Options struct {
// How much memory a request is allowed to consume in bytes, as a limit on
// the size of incoming request bodies and on responses generated
MaxMemory int64 MaxMemory int64
MaxResponseSize int64
MaxResponseTime time.Duration // Maximum duration of a request, for those requests that allow user
// control over timing (e.g. /delay)
MaxDuration time.Duration
} }
// HTTPBin contains the business logic // HTTPBin contains the business logic
...@@ -166,11 +176,18 @@ func (h *HTTPBin) Handler() http.Handler { ...@@ -166,11 +176,18 @@ func (h *HTTPBin) Handler() http.Handler {
return handler return handler
} }
// NewHTTPBin creates a new HTTPBin // NewHTTPBin creates a new HTTPBin instance with default options
func NewHTTPBin(options *Options) *HTTPBin { func NewHTTPBin() *HTTPBin {
if options == nil { return &HTTPBin{
options = &Options{} options: &Options{
MaxMemory: DefaultMaxMemory,
MaxDuration: DefaultMaxDuration,
},
}
} }
// NewHTTPBinWithOptions creates a new HTTPBin instance with the given options
func NewHTTPBinWithOptions(options *Options) *HTTPBin {
return &HTTPBin{ return &HTTPBin{
options: options, options: options,
} }
......
package httpbin
import (
"testing"
"time"
)
func TestNewHTTPBin__Defaults(t *testing.T) {
h := NewHTTPBin()
if h.options.MaxMemory != DefaultMaxMemory {
t.Fatalf("expected default MaxMemory == %d, got %#v", DefaultMaxMemory, h.options.MaxMemory)
}
if h.options.MaxDuration != DefaultMaxDuration {
t.Fatalf("expected default MaxDuration == %s, got %#v", DefaultMaxDuration, h.options.MaxDuration)
}
}
func TestNewHTTPBinWithOptions__Defaults(t *testing.T) {
o := &Options{
MaxDuration: 1 * time.Second,
MaxMemory: 1024,
}
h := NewHTTPBinWithOptions(o)
if h.options.MaxMemory != o.MaxMemory {
t.Fatalf("expected MaxMemory == %d, got %#v", o.MaxMemory, h.options.MaxMemory)
}
if h.options.MaxDuration != o.MaxDuration {
t.Fatalf("expected MaxDuration == %s, got %#v", o.MaxDuration, h.options.MaxDuration)
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment