Add --http-allow-param-hash

This commit is contained in:
Leonid Bugaev
2015-07-09 15:30:06 +05:00
parent 413f50129f
commit 5a23573cfe
7 changed files with 94 additions and 18 deletions
+20 -6
View File
@@ -15,6 +15,7 @@ func NewHTTPModifier(config *HTTPModifierConfig) *HTTPModifier {
len(config.urlRewrite) == 0 &&
len(config.headerFilters) == 0 &&
len(config.headerHashFilters) == 0 &&
len(config.paramHashFilters) == 0 &&
len(config.headers) == 0 &&
len(config.methods) == 0 {
return nil
@@ -60,15 +61,28 @@ func (m *HTTPModifier) Rewrite(payload []byte) (response []byte) {
for _, f := range m.config.headerHashFilters {
value, s, _, _ := proto.Header(payload, f.name)
if s == -1 {
return
if s != -1 {
hasher := fnv.New32a()
hasher.Write(value)
if (hasher.Sum32() % 100) >= f.percent {
return
}
}
}
}
hasher := fnv.New32a()
hasher.Write(value)
if len(m.config.paramHashFilters) > 0 {
for _, f := range m.config.paramHashFilters {
value, s, _ := proto.PathParam(payload, f.name)
if (hasher.Sum32() % 100) >= f.percent {
return
if s != -1 {
hasher := fnv.New32a()
hasher.Write(value)
if (hasher.Sum32() % 100) >= f.percent {
return
}
}
}
}
+8 -7
View File
@@ -14,7 +14,8 @@ type HTTPModifierConfig struct {
urlRegexp HTTPUrlRegexp
urlRewrite UrlRewriteMap
headerFilters HTTPHeaderFilters
headerHashFilters HTTPHeaderHashFilters
headerHashFilters HTTPHashFilters
paramHashFilters HTTPHashFilters
headers HTTPHeaders
methods HTTPMethods
@@ -50,20 +51,20 @@ func (h *HTTPHeaderFilters) Set(value string) error {
}
//
// Handling of --http-allow-header-hash options
// Handling of --http-allow-header-hash and --http-allow-param-hash options
//
type headerHashFilter struct {
type hashFilter struct {
name []byte
percent uint32
}
type HTTPHeaderHashFilters []headerHashFilter
type HTTPHashFilters []hashFilter
func (h *HTTPHeaderHashFilters) String() string {
func (h *HTTPHashFilters) String() string {
return fmt.Sprint(*h)
}
func (h *HTTPHeaderHashFilters) Set(value string) error {
func (h *HTTPHashFilters) Set(value string) error {
valArr := strings.SplitN(value, ":", 2)
if len(valArr) < 2 {
return errors.New("need both header and value, colon-delimited (ex. user_id:1/2).")
@@ -78,7 +79,7 @@ func (h *HTTPHeaderHashFilters) Set(value string) error {
num, _ = strconv.ParseUint(fracArr[0], 10, 64)
den, _ = strconv.ParseUint(fracArr[1], 10, 64)
var f headerHashFilter
var f hashFilter
f.name = []byte(valArr[0])
f.percent = uint32((float64(num) / float64(den)) * 100)
*h = append(*h, f)
+2 -2
View File
@@ -24,8 +24,8 @@ func TestHTTPHeaderFilters(t *testing.T) {
}
}
func TestHTTPHeaderHashFilters(t *testing.T) {
filters := HTTPHeaderHashFilters{}
func TestHTTPHashFilters(t *testing.T) {
filters := HTTPHashFilters{}
err := filters.Set("Header1:1/2")
if err != nil {
+29 -3
View File
@@ -69,7 +69,7 @@ func TestHTTPModifierURLRewrite(t *testing.T) {
}
func TestHTTPModifierHeaderHashFilters(t *testing.T) {
filters := HTTPHeaderHashFilters{}
filters := HTTPHashFilters{}
filters.Set("Header2:1/2")
modifier := NewHTTPModifier(&HTTPModifierConfig{
@@ -80,8 +80,8 @@ func TestHTTPModifierHeaderHashFilters(t *testing.T) {
return []byte("POST / HTTP/1.1\r\n" + string(header) + "Content-Length: 7\r\nHost: www.w3.org\r\n\r\na=1&b=2")
}
if p := modifier.Rewrite(payload([]byte(""))); len(p) > 0 {
t.Error("Request should not pass filters, Header2 does not exist")
if p := modifier.Rewrite(payload([]byte(""))); len(p) == 0 {
t.Error("Request should pass filters if Header does not exist")
}
if p := modifier.Rewrite(payload([]byte("Header2: 3\r\n"))); len(p) > 0 {
@@ -93,6 +93,32 @@ func TestHTTPModifierHeaderHashFilters(t *testing.T) {
}
}
func TestHTTPModifierParamHashFilters(t *testing.T) {
filters := HTTPHashFilters{}
filters.Set("user_id:1/2")
modifier := NewHTTPModifier(&HTTPModifierConfig{
paramHashFilters: filters,
})
payload := func(value []byte) []byte {
return []byte("POST /" + string(value) + " HTTP/1.1\r\nContent-Length: 7\r\nHost: www.w3.org\r\n\r\na=1&b=2")
}
if p := modifier.Rewrite(payload([]byte(""))); len(p) == 0 {
t.Error("Request should pass filters if param does not exist")
}
if p := modifier.Rewrite(payload([]byte("?user_id=3"))); len(p) > 0 {
t.Error("Request should not pass filters", string(p))
}
if p := modifier.Rewrite(payload([]byte("?user_id=1"))); len(p) == 0 {
t.Error("Request should pass filters")
}
}
func TestHTTPModifierHeaders(t *testing.T) {
headers := HTTPHeaders{}
headers.Set("Header1:1")
+18
View File
@@ -86,6 +86,24 @@ func SetPath(payload, path []byte) []byte {
return byteutils.Replace(payload, start, start+end, path)
}
func PathParam(payload, name []byte) (value []byte, valueStart, valueEnd int) {
path := Path(payload)
if paramStart := bytes.Index(path, append(name, '=')); paramStart != -1 {
valueStart := paramStart + len(name) + 1
paramEnd := bytes.IndexByte(path[valueStart:], '&')
if paramEnd == -1 { // It is final param
paramEnd = len(path)
} else {
paramEnd += valueStart
}
return path[valueStart:paramEnd], valueStart, paramEnd
} else {
return []byte(""), -1, -1
}
}
func SetHost(payload, url, host []byte) []byte {
// If this is HTTP 1.0 traffic or proxy traffic it may include host right into path variable, so instead of setting Host header we rewrite Path
// Fix for https://github.com/buger/gor/issues/156
+15
View File
@@ -89,6 +89,21 @@ func TestSetPath(t *testing.T) {
}
}
func TestPathParam(t *testing.T) {
var payload []byte
payload = []byte("POST /post?param=test&user_id=1 HTTP/1.1\r\nContent-Length: 7\r\nHost: www.w3.org\r\n\r\na=1&b=2")
if val, _, _ := PathParam(payload, []byte("param")); !bytes.Equal(val, []byte("test")) {
t.Error("Should detect attribute", string(val))
}
if val, _, _ := PathParam(payload, []byte("user_id")); !bytes.Equal(val, []byte("1")) {
t.Error("Should detect attribute", string(val))
}
}
func TestSetHostHTTP10(t *testing.T) {
var payload, payload_after []byte
+2
View File
@@ -110,6 +110,8 @@ func init() {
flag.Var(&Settings.modifierConfig.headerHashFilters, "http-allow-header-hash", "Takes a fraction of requests, consistently taking or rejecting a request based on the FNV32-1A hash of a specific header:\n\t gor --input-raw :8080 --output-http staging.com --http-allow-header-hash user-id:1/4")
flag.Var(&Settings.modifierConfig.headerHashFilters, "output-http-header-hash-filter", "WARNING: `output-http-header-hash-filter` DEPRECATED, use `--http-allow-header-hash` instead")
flag.Var(&Settings.modifierConfig.paramHashFilters, "http-allow-param-hash", "Takes a fraction of requests, consistently taking or rejecting a request based on the FNV32-1A hash of a specific GET param:\n\t gor --input-raw :8080 --output-http staging.com --http-allow-param-hash user_id:1/4")
}
func Debug(args ...interface{}) {