Skip to content

Commit

Permalink
targets: Test and refine JSONTargeter
Browse files Browse the repository at this point in the history
  • Loading branch information
tsenart committed Jul 7, 2018
1 parent eb227c2 commit 2e261e6
Show file tree
Hide file tree
Showing 2 changed files with 158 additions and 7 deletions.
75 changes: 68 additions & 7 deletions lib/targets.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,50 @@ func (t *Target) Request() (*http.Request, error) {
return req, nil
}

// Equal returns true if the target is equal to the other given target.
func (t *Target) Equal(other *Target) bool {
switch {
case t == other:
return true
case t == nil || other == nil:
return false
default:
equal := t.Method == other.Method &&
t.URL == other.URL &&
bytes.Equal(t.Body, other.Body) &&
len(t.Header) == len(other.Header)

if !equal {
return false
}

for k := range t.Header {
left, right := t.Header[k], other.Header[k]
if len(left) != len(right) {
return false
}
for i := range left {
if left[i] != right[i] {
return false
}
}
}

return true
}
}

var (
// ErrNoTargets is returned when not enough Targets are available.
ErrNoTargets = errors.New("no targets to attack")
// ErrNilTarget is returned when the passed Target pointer is nil.
ErrNilTarget = errors.New("nil target")
// ErrNoMethod is returned by JSONTargeter when a parsed Target has
// no method.
ErrNoMethod = errors.New("target: required method is missing")
// ErrNoURL is returned by JSONTargeter when a parsed Target has no
// URL.
ErrNoURL = errors.New("target: required url is missing")
// TargetFormats contains the canonical list of the valid target
// format identifiers.
TargetFormats = []string{HTTPTargetFormat, JSONTargetFormat}
Expand Down Expand Up @@ -91,16 +130,38 @@ func NewJSONTargeter(src io.Reader, body []byte, header http.Header) Targeter {
dec.Lock()
defer dec.Unlock()

if err = dec.Decode(tgt); err == nil {
return nil
var t Target
if err = dec.Decode(&t); err != nil && err != io.EOF {
return err
} else if t.Method == "" {
return ErrNoMethod
} else if t.URL == "" {
return ErrNoURL
}

switch err {
case io.EOF:
return ErrNoTargets
default:
return err
tgt.Method = t.Method
tgt.URL = t.URL
if tgt.Body = body; len(t.Body) > 0 {
tgt.Body = t.Body
}

if tgt.Header == nil {
tgt.Header = http.Header{}
}

for k, vs := range header {
tgt.Header[k] = append(tgt.Header[k], vs...)
}

for k, vs := range t.Header {
tgt.Header[k] = append(tgt.Header[k], vs...)
}

if err == io.EOF {
err = ErrNoTargets
}

return err
}
}

Expand Down
90 changes: 90 additions & 0 deletions lib/targets_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,96 @@ func TestTargetRequest(t *testing.T) {
}
}

func TestJSONTargeter(t *testing.T) {
for _, tc := range []struct {
name string
src io.Reader
body []byte
hdr http.Header
in *Target
out *Target
err error
}{
{
name: "nil target",
src: &bytes.Buffer{},
in: nil,
out: nil,
err: ErrNilTarget,
},
{
name: "empty buffer",
src: &bytes.Buffer{},
in: &Target{},
out: &Target{},
err: ErrNoMethod,
},
{
name: "empty object",
src: strings.NewReader(`{}`),
in: &Target{},
out: &Target{},
err: ErrNoMethod,
},
{
name: "empty method",
src: strings.NewReader(`{"method": ""}`),
in: &Target{},
out: &Target{},
err: ErrNoMethod,
},
{
name: "empty url",
src: strings.NewReader(`{"method": "GET"}`),
in: &Target{},
out: &Target{},
err: ErrNoURL,
},
{
name: "bad body encoding",
src: strings.NewReader(`{"method": "GET", "url": "http://goku", "body": "NOT BASE64"}`),
in: &Target{},
out: &Target{},
err: errors.New("illegal base64 data at input byte 3"),
},
{
name: "default body",
src: strings.NewReader(`{"method": "GET", "url": "http://goku"}`),
body: []byte(`ATTACK!`),
in: &Target{},
out: &Target{Method: "GET", URL: "http://goku", Body: []byte("ATTACK!")},
},
{
name: "headers merge",
src: strings.NewReader(`{"method": "GET", "url": "http://goku", "header":{"x": ["foo"]}}`),
hdr: http.Header{"x": []string{"bar"}},
in: &Target{Header: http.Header{"y": []string{"baz"}}},
out: &Target{Method: "GET", URL: "http://goku", Header: http.Header{"y": []string{"baz"}, "x": []string{"bar", "foo"}}},
},
{
name: "no defaults",
src: strings.NewReader(`{"method": "GET", "url": "http://goku", "header":{"x": ["foo"]}, "body": "QVRUQUNLIQ=="}`),
in: &Target{},
out: &Target{Method: "GET", URL: "http://goku", Header: http.Header{"x": []string{"foo"}}, Body: []byte("ATTACK!")},
},
} {
tc := tc
t.Run(tc.name, func(t *testing.T) {
t.Parallel()

err := NewJSONTargeter(tc.src, tc.body, tc.hdr)(tc.in)
if got, want := tc.in, tc.out; !got.Equal(want) {
t.Errorf("got Target %#v, want %#v", got, want)
}

if got, want := fmt.Sprint(err), fmt.Sprint(tc.err); got != want {
t.Errorf("got error: %+v, want: %+v", got, want)
}
})
}

}

func TestNewEagerTargeter(t *testing.T) {
t.Parallel()

Expand Down

0 comments on commit 2e261e6

Please sign in to comment.