mirror of
https://github.com/buger/goreplay.git
synced 2024-04-21 12:32:02 +00:00
227 lines
5.5 KiB
Go
227 lines
5.5 KiB
Go
package main
|
|
|
|
import (
|
|
"bytes"
|
|
"crypto/rand"
|
|
"encoding/hex"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"net/http/httputil"
|
|
"strings"
|
|
"sync"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/buger/goreplay/capture"
|
|
"github.com/buger/goreplay/proto"
|
|
)
|
|
|
|
type fakeServiceCb func(string, int, []byte)
|
|
|
|
// Simple service that generate token on request, and require this token for accesing to secure area
|
|
func NewFakeSecureService(wg *sync.WaitGroup, cb fakeServiceCb) *httptest.Server {
|
|
activeTokens := make([]string, 0)
|
|
var mu sync.Mutex
|
|
|
|
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
|
|
mu.Lock()
|
|
defer mu.Unlock()
|
|
|
|
switch req.URL.Path {
|
|
case "/token":
|
|
// Generate random token
|
|
tokenLength := 10
|
|
buf := make([]byte, tokenLength)
|
|
rand.Read(buf)
|
|
token := hex.EncodeToString(buf)
|
|
activeTokens = append(activeTokens, token)
|
|
|
|
w.Write([]byte(token))
|
|
|
|
cb(req.URL.Path, 200, []byte(token))
|
|
case "/secure":
|
|
token := req.URL.Query().Get("token")
|
|
tokenFound := false
|
|
|
|
for _, t := range activeTokens {
|
|
if t == token {
|
|
tokenFound = true
|
|
break
|
|
}
|
|
}
|
|
|
|
if tokenFound {
|
|
w.WriteHeader(http.StatusAccepted)
|
|
cb(req.URL.Path, 202, nil)
|
|
} else {
|
|
w.WriteHeader(http.StatusForbidden)
|
|
cb(req.URL.Path, 403, nil)
|
|
}
|
|
}
|
|
|
|
wg.Done()
|
|
}))
|
|
|
|
return server
|
|
}
|
|
|
|
func TestFakeSecureService(t *testing.T) {
|
|
var resp, token []byte
|
|
|
|
wg := new(sync.WaitGroup)
|
|
|
|
server := NewFakeSecureService(wg, func(path string, status int, resp []byte) {
|
|
})
|
|
defer server.Close()
|
|
|
|
wg.Add(3)
|
|
|
|
client := NewHTTPClient(&HTTPOutputConfig{}).Client
|
|
rep, _ := client.Get(server.URL + "/token")
|
|
resp, _ = httputil.DumpResponse(rep, true)
|
|
token = proto.Body(resp)
|
|
|
|
// Right token
|
|
rep, _ = client.Get(server.URL + "/secure?token=" + string(token))
|
|
resp, _ = httputil.DumpResponse(rep, true)
|
|
if !bytes.Equal(proto.Status(resp), []byte("202")) {
|
|
t.Error("Valid token should return status 202:", string(proto.Status(resp)))
|
|
}
|
|
|
|
// Wrong tokens forbidden
|
|
rep, _ = client.Get(server.URL + "/secure?token=wrong")
|
|
resp, _ = httputil.DumpResponse(rep, true)
|
|
if !bytes.Equal(proto.Status(resp), []byte("403")) {
|
|
t.Error("Wrong token should returns status 403:", string(proto.Status(resp)))
|
|
}
|
|
|
|
wg.Wait()
|
|
}
|
|
|
|
func TestEchoMiddleware(t *testing.T) {
|
|
wg := new(sync.WaitGroup)
|
|
|
|
from := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
w.Header().Set("Env", "prod")
|
|
w.Header().Set("RequestPath", r.URL.Path)
|
|
wg.Done()
|
|
}))
|
|
defer from.Close()
|
|
|
|
to := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
w.Header().Set("Env", "test")
|
|
w.Header().Set("RequestPath", r.URL.Path)
|
|
wg.Done()
|
|
}))
|
|
defer to.Close()
|
|
|
|
// Catch traffic from one service
|
|
fromAddr := strings.Replace(from.Listener.Addr().String(), "[::]", "127.0.0.1", -1)
|
|
conf := RAWInputConfig{
|
|
Engine: capture.EnginePcap,
|
|
Expire: testRawExpire,
|
|
Protocol: ProtocolHTTP,
|
|
TrackResponse: true,
|
|
}
|
|
input := NewRAWInput(fromAddr, conf)
|
|
|
|
// And redirect to another
|
|
output := NewHTTPOutput(to.URL, &HTTPOutputConfig{})
|
|
|
|
plugins := &InOutPlugins{
|
|
Inputs: []PluginReader{input},
|
|
Outputs: []PluginWriter{output},
|
|
}
|
|
plugins.All = append(plugins.All, input, output)
|
|
|
|
// Start Gor
|
|
emitter := NewEmitter()
|
|
emitter.Start(plugins, "echo -n && GOR_TEST=true && ./examples/middleware/echo.sh")
|
|
|
|
// Wait till middleware initialization
|
|
time.Sleep(100 * time.Millisecond)
|
|
|
|
// Should receive 2 requests from original + 2 from replayed
|
|
client := NewHTTPClient(output.(*HTTPOutput).config).Client
|
|
|
|
for i := 0; i < 10; i++ {
|
|
wg.Add(2)
|
|
// Request should be echoed
|
|
client.Get(to.URL + "/a")
|
|
time.Sleep(5 * time.Millisecond)
|
|
client.Get(to.URL + "/b")
|
|
time.Sleep(5 * time.Millisecond)
|
|
}
|
|
|
|
wg.Wait()
|
|
emitter.Close()
|
|
}
|
|
|
|
func TestTokenMiddleware(t *testing.T) {
|
|
var resp, token []byte
|
|
|
|
wg := new(sync.WaitGroup)
|
|
|
|
from := NewFakeSecureService(wg, func(path string, status int, tok []byte) {
|
|
time.Sleep(10 * time.Millisecond)
|
|
})
|
|
defer from.Close()
|
|
|
|
to := NewFakeSecureService(wg, func(path string, status int, tok []byte) {
|
|
switch path {
|
|
case "/secure":
|
|
if status != 202 {
|
|
t.Error("Server should receive valid rewritten token")
|
|
}
|
|
}
|
|
|
|
time.Sleep(10 * time.Millisecond)
|
|
})
|
|
defer to.Close()
|
|
|
|
Settings.Middleware = "echo -n && GOR_TEST=true && go run ./examples/middleware/token_modifier.go"
|
|
|
|
fromAddr := strings.Replace(from.Listener.Addr().String(), "[::]", "127.0.0.1", -1)
|
|
conf := RAWInputConfig{
|
|
Engine: capture.EnginePcap,
|
|
Expire: testRawExpire,
|
|
Protocol: ProtocolHTTP,
|
|
TrackResponse: true,
|
|
}
|
|
// Catch traffic from one service
|
|
input := NewRAWInput(fromAddr, conf)
|
|
|
|
// And redirect to another
|
|
output := NewHTTPOutput(to.URL, &HTTPOutputConfig{})
|
|
|
|
plugins := &InOutPlugins{
|
|
Inputs: []PluginReader{input},
|
|
Outputs: []PluginWriter{output},
|
|
}
|
|
plugins.All = append(plugins.All, input, output)
|
|
|
|
// Start Gor
|
|
emitter := NewEmitter()
|
|
emitter.Start(plugins, Settings.Middleware)
|
|
|
|
// Should receive 2 requests from original + 2 from replayed
|
|
wg.Add(2)
|
|
|
|
client := NewHTTPClient(&HTTPOutputConfig{}).Client
|
|
|
|
// Sending traffic to original service
|
|
rep, _ := client.Get(to.URL + "/token")
|
|
resp, _ = httputil.DumpResponse(rep, true)
|
|
token = proto.Body(resp)
|
|
|
|
rep, _ = client.Get(to.URL + "/secure?token=" + string(token))
|
|
resp, _ = httputil.DumpResponse(rep, true)
|
|
if !bytes.Equal(proto.Status(resp), []byte("202")) {
|
|
t.Error("Valid token should return 202:", proto.Status(resp))
|
|
}
|
|
|
|
wg.Wait()
|
|
emitter.Close()
|
|
Settings.Middleware = ""
|
|
}
|