Merge remote-tracking branch 'upstream/master'

This commit is contained in:
Leonid Bugaev
2017-07-20 21:09:04 +03:00
33 changed files with 413 additions and 61 deletions
+2 -2
View File
@@ -36,7 +36,7 @@ under the terms of the GNU Lesser General Public License versions 3.0
5. Fees and Payment. The Software license fees will be due and payable in full as set forth in the applicable invoice or at the time of purchase. If the Software does not function properly within two weeks of purchase, please contact us within those two weeks for a refund. You shall be responsible for all taxes, withholdings, duties and levies arising from the order (excluding taxes based on the net income of GoReplay LLC).
6. Support, Maintenance and Services. Subject to the terms and conditions of this Agreement, as set forth in your invoice, and as set forth on the GoReplay Pro support page (https://github.com/buger/gor/wiki/Pro-Support), support and maintenance services may be included with the purchase of your license subscription.
6. Support, Maintenance and Services. Subject to the terms and conditions of this Agreement, as set forth in your invoice, and as set forth on the GoReplay Pro support page (https://github.com/buger/goreplay/wiki/Pro-Support), support and maintenance services may be included with the purchase of your license subscription.
7. Term of Agreement.
@@ -72,7 +72,7 @@ In no event will GoReplay LLC liability exceed the Software license price as ind
13.1 Entire Agreement. This Agreement sets forth our entire agreement with respect to the Software and the subject matter hereof and supersedes all prior and contemporaneous understandings and agreements whether written or oral.
13.2 Amendment. GoReplay LLC reserves the right, in its sole discretion, to amend this Agreement from time. Amendments to this Agreement can be located at: https://github.com/buger/gor/blob/master/COMM-LICENSE.
13.2 Amendment. GoReplay LLC reserves the right, in its sole discretion, to amend this Agreement from time. Amendments to this Agreement can be located at: https://github.com/buger/goreplay/blob/master/COMM-LICENSE.
13.3 Assignment. You may not assign this Agreement or any of its rights under this Agreement without the prior written consent of GoReplay LLC and any attempted assignment without such consent shall be void.
+1 -1
View File
@@ -22,4 +22,4 @@ ADD . /go/src/github.com/buger/gor-pro/
RUN wget http://archive.apache.org/dist/commons/io/binaries/commons-io-2.4-bin.tar.gz && tar xzf commons-io-2.4-bin.tar.gz && cd commons-io-2.4 && mv commons-io-2.4.jar /tmp/
RUN wget http://archive.apache.org/dist/commons/codec/binaries/commons-codec-1.9-bin.tar.gz && tar xzf commons-codec-1.9-bin.tar.gz
RUN javac -cp commons-io-2.4/commons-io-2.4.jar -cp commons-codec-1.9/commons-codec-1.9.jar ./examples/middleware/echo.java
RUN go get
RUN go get
+24
View File
@@ -0,0 +1,24 @@
FROM golang:latest
RUN apt-get update && apt-get install ruby vim-common -y
# Install Java for middleware testing
RUN echo "deb http://ppa.launchpad.net/webupd8team/java/ubuntu trusty main" | tee /etc/apt/sources.list.d/webupd8team-java.list
RUN echo "deb-src http://ppa.launchpad.net/webupd8team/java/ubuntu trusty main" | tee -a /etc/apt/sources.list.d/webupd8team-java.list
RUN apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys EEA14886
RUN apt-get update -y
RUN echo oracle-java7-installer shared/accepted-oracle-license-v1-1 select true | /usr/bin/debconf-set-selections
RUN apt-get install oracle-java8-installer -y
RUN apt-get install flex bison -y
RUN wget http://www.tcpdump.org/release/libpcap-1.7.4.tar.gz && tar xzf libpcap-1.7.4.tar.gz && cd libpcap-1.7.4 && ./configure && make install
RUN go get github.com/google/gopacket
RUN go get -u github.com/golang/lint/golint
WORKDIR /go/src/github.com/buger/goreplay/
ADD . /go/src/github.com/buger/goreplay/
RUN wget http://archive.apache.org/dist/commons/io/binaries/commons-io-2.4-bin.tar.gz && tar xzf commons-io-2.4-bin.tar.gz && cd commons-io-2.4 && mv commons-io-2.4.jar /tmp/
RUN wget http://archive.apache.org/dist/commons/codec/binaries/commons-codec-1.9-bin.tar.gz && tar xzf commons-codec-1.9-bin.tar.gz
RUN javac -cp commons-io-2.4/commons-io-2.4.jar -cp commons-codec-1.9/commons-codec-1.9.jar ./examples/middleware/echo.java
RUN go get
+1 -1
View File
@@ -1,5 +1,5 @@
SOURCE = emitter.go gor.go gor_stat.go input_dummy.go input_file.go input_raw.go input_tcp.go limiter.go output_dummy.go output_null.go output_file.go input_http.go output_http.go output_tcp.go plugins.go settings.go test_input.go elasticsearch.go http_modifier.go http_modifier_settings.go http_client.go middleware.go protocol.go output_file_settings.go tcp_client.go output_binary.go
SOURCE_PATH = /go/src/github.com/buger/gor-pro/
PORT = 8000
FADDR = :8000
CONTAINER=gor-pro
+7 -5
View File
@@ -1,9 +1,11 @@
[![GitHub release](https://img.shields.io/github/release/buger/gor.svg?maxAge=3600)](https://github.com/buger/gor/releases) [![codebeat](https://codebeat.co/badges/6427d589-a78e-416c-a546-d299b4089893)](https://codebeat.co/projects/github-com-buger-gor) [![Go Report Card](https://goreportcard.com/badge/github.com/buger/gor)](https://goreportcard.com/report/github.com/buger/gor) [![Join the chat at https://gitter.im/buger/gor](https://badges.gitter.im/buger/gor.svg)](https://gitter.im/buger/gor?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
[![GitHub release](https://img.shields.io/github/release/buger/gor.svg?maxAge=3600)](https://github.com/buger/goreplay/releases) [![codebeat](https://codebeat.co/badges/6427d589-a78e-416c-a546-d299b4089893)](https://codebeat.co/projects/github-com-buger-gor) [![Go Report Card](https://goreportcard.com/badge/github.com/buger/gor)](https://goreportcard.com/report/github.com/buger/gor) [![Join the chat at https://gitter.im/buger/gor](https://badges.gitter.im/buger/gor.svg)](https://gitter.im/buger/gor?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
![Go Replay](http://i.imgur.com/ZG2ki5n.png)
## https://goreplay.org/
## We just released a new version, see announcement https://leonsbox.com/goreplay-v0-16-and-4th-anniversary-5408b1fd72e0
## About
GoReplay is the simplest and safest way to test your app using real traffic before you put it into production.
@@ -18,17 +20,17 @@ Here is basic workflow: The listener server catches http traffic and sends it to
![Diagram](http://i.imgur.com/9mqj2SK.png)
Check [latest documentation](http://github.com/buger/gor/wiki).
Check [latest documentation](http://github.com/buger/goreplay/wiki).
## Installation
Download latest binary from https://github.com/buger/gor/releases or [compile by yourself](https://github.com/buger/gor/wiki/Compilation).
Download latest binary from https://github.com/buger/goreplay/releases or [compile by yourself](https://github.com/buger/goreplay/wiki/Compilation).
## Getting started
The most basic setup will be `sudo ./gor --input-raw :8000 --output-stdout` which acts like tcpdump.
If you already have test environment you can start replaying: `sudo ./gor --input-raw :8000 --output-http http://staging.env`.
See the our [documentation](https://github.com/buger/gor/wiki/) and [Getting started](https://github.com/buger/gor/wiki/Getting-Started) page for more info.
See the our [documentation](https://github.com/buger/goreplay/wiki/) and [Getting started](https://github.com/buger/goreplay/wiki/Getting-Started) page for more info.
## Newsletter
Subscribe to our [newsletter](https://www.getdrip.com/forms/89690474/submissions/new) to stay informed about the latest features and changes to Gor project.
@@ -39,7 +41,7 @@ We have created a [GoReplay PRO](https://goreplay.org/pro.html) extension which
## Problems?
If you have a problem, please review the [FAQ](https://github.com/buger/gor/wiki/FAQ) and [Troubleshooting](https://github.com/buger/gor/wiki/Troubleshooting) wiki pages. Searching the [issues](https://github.com/buger/gor/issues) for your problem is also a good idea.
If you have a problem, please review the [FAQ](https://github.com/buger/goreplay/wiki/FAQ) and [Troubleshooting](https://github.com/buger/goreplay/wiki/Troubleshooting) wiki pages. Searching the [issues](https://github.com/buger/goreplay/issues) for your problem is also a good idea.
All bug-reports and suggestions should go though Github Issues or our [Google Group](https://groups.google.com/forum/#!forum/gor-users) (you can just send email to gor-users@googlegroups.com).
If you have a private question feel free to send email to support@gortool.com.
+1 -1
View File
@@ -2,7 +2,7 @@ package main
import (
"encoding/json"
"github.com/buger/goreplay/proto"
"github.com/buger/gor-pro/proto"
"github.com/mattbaird/elastigo/lib"
"log"
"regexp"
+3
View File
@@ -103,6 +103,9 @@ func CopyMulty(src io.Reader, writers ...io.Writer) (err error) {
if Settings.prettifyHTTP {
payload = prettifyHTTP(payload)
if len(payload) == 0 {
continue
}
}
if Settings.splitOutput {
+57
View File
@@ -0,0 +1,57 @@
#!/usr/bin/env node
const readline = require("readline");
const StringDecoder = require("string_decoder").StringDecoder
const rl = readline.createInterface({
input: process.stdin
});
var ignoreIds = new Set();
var ignoreAddresses = "/api";
const decoder = new StringDecoder("utf8");
function convertHexString(hex) {
var bytes = [];
for (var i = 0; i < hex.length - 1; i += 2) {
bytes.push(parseInt(hex.substr(i, 2), 16));
}
return decoder.write(Buffer.from(bytes));
}
function log(output) {
console.error("===================");
console.error(output);
}
function shouldOutputLine(request) {
const components = request.split("\n");
const header = components[0].split(" ");
const type = parseInt(header[0]);
const tag = header[1];
if (type === 3) {
return true;
}
if (type === 1) {
// Check if it's oauth
const endpoint = components[1].split(" ")[1];
if (!endpoint.startsWith(ignoreAddresses)) {
ignoreIds.add(tag);
return false;
}
} else if (type === 2) {
if (ignoreIds.has(tag)) {
ignoreIds.delete(tag);
return false;
}
}
return true;
}
rl.on("line", (input) => {
const str = convertHexString(input);
console.log(input);
if (shouldOutputLine(str)) {
log(str);
}
});
+1 -1
View File
@@ -24,7 +24,7 @@ import (
"bytes"
"encoding/hex"
"fmt"
"github.com/buger/gor/proto"
"github.com/buger/goreplay/proto"
"os"
)
+7 -6
View File
@@ -32,7 +32,10 @@ func loggingMiddleware(next http.Handler) http.Handler {
})
}
var closeCh chan int
func main() {
closeCh = make(chan int)
// // Don't exit on panic
// defer func() {
// if r := recover(); r != nil {
@@ -52,7 +55,7 @@ func main() {
}
dir, _ := os.Getwd()
log.Println("Started example file server for current dirrectory on address ", args[1])
log.Println("Started example file server for current directory on address ", args[1])
log.Fatal(http.ListenAndServe(args[1], loggingMiddleware(http.FileServer(http.Dir(dir)))))
} else {
@@ -84,17 +87,15 @@ func main() {
if Settings.exitAfter > 0 {
log.Println("Running gor for a duration of", Settings.exitAfter)
closeCh := make(chan int)
closeCh = make(chan int)
time.AfterFunc(Settings.exitAfter, func() {
log.Println("Stopping gor after", Settings.exitAfter)
close(closeCh)
})
Start(closeCh)
} else {
Start(nil)
}
Start(closeCh)
}
func finalize() {
+1 -1
View File
@@ -15,7 +15,7 @@ import (
"syscall"
"time"
"github.com/buger/goreplay/proto"
"github.com/buger/gor-pro/proto"
)
var httpMu sync.Mutex
+16 -1
View File
@@ -4,7 +4,7 @@ import (
"bytes"
"hash/fnv"
"github.com/buger/goreplay/proto"
"github.com/buger/gor-pro/proto"
)
type HTTPModifier struct {
@@ -16,6 +16,7 @@ func NewHTTPModifier(config *HTTPModifierConfig) *HTTPModifier {
if len(config.urlRegexp) == 0 &&
len(config.urlNegativeRegexp) == 0 &&
len(config.urlRewrite) == 0 &&
len(config.headerRewrite) == 0 &&
len(config.headerFilters) == 0 &&
len(config.headerNegativeFilters) == 0 &&
len(config.headerHashFilters) == 0 &&
@@ -153,5 +154,19 @@ func (m *HTTPModifier) Rewrite(payload []byte) (response []byte) {
}
}
if len(m.config.headerRewrite) > 0 {
for _, f := range m.config.headerRewrite {
value := proto.Header(payload, f.header)
if len(value) == 0 {
break
}
if f.src.Match(value) {
newValue := f.src.ReplaceAll(value, f.target)
payload = proto.SetHeader(payload, f.header, newValue)
}
}
}
return payload
}
+38
View File
@@ -13,6 +13,7 @@ type HTTPModifierConfig struct {
urlNegativeRegexp HTTPUrlRegexp
urlRegexp HTTPUrlRegexp
urlRewrite UrlRewriteMap
headerRewrite HeaderRewriteMap
headerFilters HTTPHeaderFilters
headerNegativeFilters HTTPHeaderFilters
headerHashFilters HTTPHashFilters
@@ -196,6 +197,43 @@ func (r *UrlRewriteMap) Set(value string) error {
return nil
}
//
// Handling of --http-rewrite-header option
//
type headerRewrite struct {
header []byte
src *regexp.Regexp
target []byte
}
type HeaderRewriteMap []headerRewrite
func (r *HeaderRewriteMap) String() string {
return fmt.Sprint(*r)
}
func (r *HeaderRewriteMap) Set(value string) error {
headerArr := strings.SplitN(value, ":", 2)
if len(headerArr) < 2 {
return errors.New("need both header, regexp and rewrite target, colon-delimited (ex. Header: regexp,target)")
}
header := headerArr[0]
valArr := strings.SplitN(strings.TrimSpace(headerArr[1]), ",", 2)
if len(valArr) < 2 {
return errors.New("need both header, regexp and rewrite target, colon-delimited (ex. Header: regexp,target)")
}
regexp, err := regexp.Compile(valArr[0])
if err != nil {
return err
}
*r = append(*r, headerRewrite{header: []byte(header), src: regexp, target: []byte(valArr[1])})
return nil
}
//
// Handling of --http-allow-url option
//
+22 -1
View File
@@ -2,7 +2,7 @@ package main
import (
"bytes"
"github.com/buger/gor/proto"
"github.com/buger/goreplay/proto"
"testing"
)
@@ -107,6 +107,27 @@ func TestHTTPModifierURLRewrite(t *testing.T) {
}
}
func TestHTTPModifierHeaderRewrite(t *testing.T) {
var header, newHeader []byte
rewrites := HeaderRewriteMap{}
payload := []byte("GET / HTTP/1.1\r\nContent-Length: 7\r\nHost: www.w3.org\r\n\r\na=1&b=2")
err := rewrites.Set("Host: (.*).w3.org,$1.beta.w3.org")
if err != nil {
t.Error("Should not error", err)
}
modifier := NewHTTPModifier(&HTTPModifierConfig{
headerRewrite: rewrites,
})
header = []byte("www.beta.w3.org")
if newHeader = proto.Header(modifier.Rewrite(payload), []byte("Host")); !bytes.Equal(newHeader, header) {
t.Error("Request header should have been rewritten, wasn't", string(newHeader), string(header))
}
}
func TestHTTPModifierHeaderHashFilters(t *testing.T) {
filters := HTTPHashFilters{}
filters.Set("Header2:1/2")
+2 -1
View File
@@ -1,7 +1,7 @@
package main
import (
"github.com/buger/goreplay/proto"
"github.com/buger/gor-pro/proto"
"bytes"
"compress/gzip"
"strconv"
@@ -52,6 +52,7 @@ func prettifyHTTP(p []byte) []byte {
if err != nil {
Debug("[Prettifier] GZIP encoding error:", err)
return []byte{}
}
content, _ = ioutil.ReadAll(g)
+7
View File
@@ -322,6 +322,13 @@ func (i *FileInput) emit() {
}
log.Printf("FileInput: end of file '%s'\n", i.path)
// For now having fixed timeout is temporary solution
// Further should be modified, so outputs can report if their queue empty or not
time.Sleep(time.Second)
if closeCh != nil {
close(closeCh)
}
}
func (i *FileInput) Close() error {
+30 -7
View File
@@ -4,6 +4,7 @@ import (
"bufio"
"bytes"
"fmt"
"crypto/tls"
"io"
"log"
"net"
@@ -13,15 +14,23 @@ import (
// TCPInput used for internal communication
type TCPInput struct {
data chan []byte
address string
listener net.Listener
address string
config *TCPInputConfig
}
type TCPInputConfig struct {
secure bool
certificatePath string
keyPath string
}
// NewTCPInput constructor for TCPInput, accepts address with port
func NewTCPInput(address string) (i *TCPInput) {
func NewTCPInput(address string, config *TCPInputConfig) (i *TCPInput) {
i = new(TCPInput)
i.data = make(chan []byte, 1000)
i.address = address
i.config = config
i.listen(address)
@@ -36,16 +45,30 @@ func (i *TCPInput) Read(data []byte) (int, error) {
}
func (i *TCPInput) listen(address string) {
listener, err := net.Listen("tcp", address)
i.listener = listener
if i.config.secure {
cer, err := tls.LoadX509KeyPair(i.config.certificatePath, i.config.keyPath)
if err != nil {
log.Fatal("Error while loading --input-file certificate:", err)
}
if err != nil {
log.Fatal("Can't start:", err)
config := &tls.Config{Certificates: []tls.Certificate{cer}}
listener, err := tls.Listen("tcp", address, config)
if err != nil {
log.Fatal("Can't start --input-tcp with secure connection:", err)
}
i.listener = listener
} else {
listener, err := net.Listen("tcp", address)
if err != nil {
log.Fatal("Can't start:", err)
}
i.listener = listener
}
go func() {
for {
conn, err := listener.Accept()
conn, err := i.listener.Accept()
if err != nil {
log.Println("Error while Accept()", err)
+89 -1
View File
@@ -2,8 +2,18 @@ package main
import (
"io"
"os"
"log"
"net"
"io/ioutil"
"crypto/x509"
"crypto/rsa"
"crypto/rand"
"crypto/tls"
"encoding/pem"
"math/big"
"time"
"bytes"
"sync"
"testing"
)
@@ -12,7 +22,7 @@ func TestTCPInput(t *testing.T) {
wg := new(sync.WaitGroup)
quit := make(chan int)
input := NewTCPInput("127.0.0.1:0")
input := NewTCPInput("127.0.0.1:0", &TCPInputConfig{})
output := NewTestOutput(func(data []byte) {
wg.Done()
})
@@ -46,3 +56,81 @@ func TestTCPInput(t *testing.T) {
close(quit)
}
func genCertificate(template *x509.Certificate) ([]byte, []byte) {
priv, _ := rsa.GenerateKey(rand.Reader, 2048)
serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
serialNumber, _ := rand.Int(rand.Reader, serialNumberLimit)
template.SerialNumber = serialNumber
template.BasicConstraintsValid = true
template.NotBefore = time.Now()
template.NotAfter = time.Now().Add(time.Hour)
derBytes, _ := x509.CreateCertificate(rand.Reader, template, template, &priv.PublicKey, priv)
var certPem, keyPem bytes.Buffer
pem.Encode(&certPem, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes})
pem.Encode(&keyPem, &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(priv)})
return certPem.Bytes(), keyPem.Bytes()
}
func TestTCPInputSecure(t *testing.T) {
serverCertPem, serverPrivPem := genCertificate(&x509.Certificate{
DNSNames: []string{"localhost"},
IPAddresses: []net.IP{net.ParseIP("127.0.0.1"), net.ParseIP("::")},
})
serverCertPemFile, _ := ioutil.TempFile("", "server.crt")
serverCertPemFile.Write(serverCertPem)
serverCertPemFile.Close()
serverPrivPemFile, _ := ioutil.TempFile("", "server.key")
serverPrivPemFile.Write(serverPrivPem)
serverPrivPemFile.Close()
defer func(){
os.Remove(serverPrivPemFile.Name())
os.Remove(serverCertPemFile.Name())
}()
wg := new(sync.WaitGroup)
quit := make(chan int)
input := NewTCPInput("127.0.0.1:0", &TCPInputConfig{
secure: true,
certificatePath: serverCertPemFile.Name(),
keyPath: serverPrivPemFile.Name(),
})
output := NewTestOutput(func(data []byte) {
wg.Done()
})
Plugins.Inputs = []io.Reader{input}
Plugins.Outputs = []io.Writer{output}
go Start(quit)
conf := &tls.Config{
InsecureSkipVerify: true,
}
conn, err := tls.Dial("tcp", input.listener.Addr().String(), conf)
if err != nil {
t.Fatal(err)
}
defer conn.Close()
msg := []byte("1 1 1\nGET / HTTP/1.1\r\n\r\n")
for i := 0; i < 100; i++ {
wg.Add(1)
conn.Write(msg)
conn.Write([]byte(payloadSeparator))
}
wg.Wait()
close(quit)
}
+1 -1
View File
@@ -4,7 +4,7 @@ import (
"bytes"
"fmt"
"github.com/Shopify/sarama"
"github.com/buger/goreplay/proto"
"github.com/buger/gor-pro/proto"
)
// KafkaConfig should contains required information to
+6 -4
View File
@@ -30,12 +30,13 @@ gor.on('request', function(data) {
// GET / HTTP/1.1\r\n
// User-Agent: Golang\r\n
// \r\n
data.html
data.http
// Meta is an array size of 3, containing:
// Meta is an array size of 4, containing:
// 1. request type - 1, 2 or 3 (which maps to `request`, `respose` and `replay`)
// 2. timestamp of when request was made (for responses it is time of request start too)
// 3. latency - time difference between request start and finish. For `request` is zero.
// 2. uuid - request unique identifier. Request responses have the same ID as their request.
// 3. timestamp of when request was made (for responses it is time of request start too)
// 4. latency - time difference between request start and finish. For `request` is zero.
data.meta
// Unique request ID. It should be same for `request`, `response` and `replay` events of the same request.
@@ -97,6 +98,7 @@ gor.on("request", function(req) {
Package expose following functions to process raw HTTP payloads:
* `init` - initialize middleware object, start reading from STDIN.
* `httpPath` - URL path of the request: `gor.httpPath(req.http)`
* `httpMethod` - Http method: 'GET', 'POST', etc. `gor.httpMethod(req.http)`.
* `setHttpPath` - update URL path: `req.http = gor.setHttpPath(req.http, newPath)`
* `httpPathParam` - get param from URL path: `gor.httpPathParam(req.http, queryParam)`
* `setHttpPathParam` - set URL param: `req.http = gor.setHttpPathParam(req.http, queryParam, value)`
+27 -6
View File
@@ -183,6 +183,11 @@ function searchResponses(id, searchPattern, callback) {
// \r\n
// hello
function httpMethod(payload) {
var pEnd = payload.indexOf(' ');
return payload.slice(0, pEnd).toString("ascii");
}
function httpPath(payload) {
var pStart = payload.indexOf(' ') + 1;
var pEnd = payload.indexOf(' ', pStart);
@@ -255,14 +260,17 @@ function httpHeader(payload, name) {
}
header.start = -1
header.valueStart = -1
continue;
} else if (c == 10) { // "\r"
i++
continue;
} else if (c == 58) { // ":" Header/value separator symbol
header.valueStart = i + 1;
i++
continue;
if (header.valueStart == -1) {
header.valueStart = i + 1;
i++
continue;
}
}
if (header.start == -1) header.start = i;
@@ -348,6 +356,7 @@ module.exports = {
parseMessage: parseMessage,
searchResponses: searchResponses,
httpPath: httpPath,
httpMethod: httpMethod,
setHttpPath: setHttpPath,
httpPathParam: httpPathParam,
setHttpPathParam: setHttpPathParam,
@@ -368,7 +377,7 @@ module.exports = {
// =========== Tests ==============
function testRunner(){
["init", "parseMessage", "httpPath", "setHttpHeader", "httpPathParam", "httpHeader", "httpBody", "setHttpBody", "httpBodyParam", "httpCookie", "setHttpCookie"].forEach(function(t){
["init", "parseMessage", "httpMethod", "httpPath", "setHttpHeader", "httpPathParam", "httpHeader", "httpBody", "setHttpBody", "httpBodyParam", "httpCookie", "setHttpCookie"].forEach(function(t){
console.log(`====== Start ${t} =======`)
eval(`TEST_${t}()`)
console.log(`====== End ${t} =======`)
@@ -448,6 +457,18 @@ function TEST_httpPath() {
}
}
function TEST_httpMethod() {
const examplePayload = "GET /test HTTP/1.1\r\n\r\n";
let payload = Buffer.from(examplePayload);
let method = httpMethod(payload);
if (method != "GET") {
return fail(`Path '${method}' != 'GET'`)
}
}
function TEST_httpPathParam() {
let p = Buffer.from("GET / HTTP/1.1\r\n\r\n");
@@ -511,9 +532,9 @@ function TEST_httpBodyParam() {
}
function TEST_httpHeader() {
const examplePayload = "GET / HTTP/1.1\r\nUser-Agent: Node\r\nContent-Length:5\r\n\r\nhello";
const examplePayload = "GET / HTTP/1.1\r\nHost: localhost:3000\r\nUser-Agent: Node\r\nContent-Length:5\r\n\r\nhello";
let expected = {"User-Agent": "Node", "Content-Length": "5"}
let expected = {"Host": "localhost:3000", "User-Agent": "Node", "Content-Length": "5"}
Object.keys(expected).forEach(function(name){
let payload = Buffer.from(examplePayload);
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "goreplay_middleware",
"version": "0.1.11",
"version": "0.1.13",
"description": "Package for writing middleware for GoReplay https://goreplay.org",
"main": "middleware.js",
"scripts": {
+1 -1
View File
@@ -4,7 +4,7 @@ import (
"encoding/json"
"github.com/Shopify/sarama"
"github.com/Shopify/sarama/mocks"
"github.com/buger/goreplay/proto"
"github.com/buger/gor-pro/proto"
"io"
"log"
"strings"
+13 -2
View File
@@ -1,6 +1,7 @@
package main
import (
"crypto/tls"
"fmt"
"io"
"log"
@@ -16,14 +17,20 @@ type TCPOutput struct {
limit int
buf chan []byte
bufStats *GorStat
config *TCPOutputConfig
}
type TCPOutputConfig struct {
secure bool
}
// NewTCPOutput constructor for TCPOutput
// Initialize 10 workers which hold keep-alive connection
func NewTCPOutput(address string) io.Writer {
func NewTCPOutput(address string, config *TCPOutputConfig) io.Writer {
o := new(TCPOutput)
o.address = address
o.config = config
o.buf = make(chan []byte, 100)
if Settings.outputTCPStats {
@@ -89,7 +96,11 @@ func (o *TCPOutput) Write(data []byte) (n int, err error) {
}
func (o *TCPOutput) connect(address string) (conn net.Conn, err error) {
conn, err = net.Dial("tcp", address)
if o.config.secure {
conn, err = tls.Dial("tcp", address, &tls.Config{})
} else {
conn, err = net.Dial("tcp", address)
}
return
}
+2 -2
View File
@@ -17,7 +17,7 @@ func TestTCPOutput(t *testing.T) {
wg.Done()
})
input := NewTestInput()
output := NewTCPOutput(listener.Addr().String())
output := NewTCPOutput(listener.Addr().String(), &TCPOutputConfig{})
Plugins.Inputs = []io.Reader{input}
Plugins.Outputs = []io.Writer{output}
@@ -69,7 +69,7 @@ func BenchmarkTCPOutput(b *testing.B) {
wg.Done()
})
input := NewTestInput()
output := NewTCPOutput(listener.Addr().String())
output := NewTCPOutput(listener.Addr().String(), &TCPOutputConfig{})
Plugins.Inputs = []io.Reader{input}
Plugins.Outputs = []io.Writer{output}
+2 -2
View File
@@ -110,11 +110,11 @@ func InitPlugins() {
}
for _, options := range Settings.inputTCP {
registerPlugin(NewTCPInput, options)
registerPlugin(NewTCPInput, options, &Settings.inputTCPConfig)
}
for _, options := range Settings.outputTCP {
registerPlugin(NewTCPOutput, options)
registerPlugin(NewTCPOutput, options, &Settings.outputTCPConfig)
}
for _, options := range Settings.inputFile {
+16 -1
View File
@@ -18,7 +18,7 @@ package proto
import (
"bytes"
"github.com/buger/gor/byteutils"
"github.com/buger/gor-pro/byteutils"
)
// In HTTP newline defined by 2 bytes (for both windows and *nix support)
@@ -343,8 +343,23 @@ func Body(payload []byte) []byte {
// Path takes payload and retuns request path: Split(firstLine, ' ')[1]
func Path(payload []byte) []byte {
start := bytes.IndexByte(payload, ' ') + 1
eol := bytes.IndexByte(payload[start:], '\r')
end := bytes.IndexByte(payload[start:], ' ')
if eol > 0 && eol < end {
return payload[start : start + eol]
} else if eol == - 1 { // support for legacy clients with wrong end of lines
eol = bytes.IndexByte(payload[start:], '\n')
if eol > 0 && eol < end {
return payload[start : start + eol]
}
}
if end < 0 {
return payload[start: len(payload)]
}
return payload[start : start+end]
}
+10 -4
View File
@@ -65,13 +65,13 @@ func TestHeader(t *testing.T) {
}
func TestMIMEHeadersEndPos(t *testing.T) {
head := []byte("POST /post HTTP/1.1\r\nContent-Length: 7\r\nHost: www.w3.org")
head := []byte("POST /post HTTP/1.1\r\nContent-Length: 7\r\nHost: www.w3.org\r\n\r\n")
payload := []byte("POST /post HTTP/1.1\r\nContent-Length: 7\r\nHost: www.w3.org\r\n\r\na=1&b=2")
end := MIMEHeadersEndPos(payload)
if !bytes.Equal(payload[:end], head) {
t.Error("Wrong headers end position:", end)
t.Error("Wrong headers end position:", end, head, payload[:end])
}
}
@@ -80,10 +80,10 @@ func TestMIMEHeadersStartPos(t *testing.T) {
payload := []byte("POST /post HTTP/1.1\r\nContent-Length: 7\r\nHost: www.w3.org\r\n\r\na=1&b=2")
start := MIMEHeadersStartPos(payload)
end := MIMEHeadersEndPos(payload)
end := MIMEHeadersEndPos(payload) - 4
if !bytes.Equal(payload[start:end], headers) {
t.Error("Wrong headers end position:", start, end)
t.Error("Wrong headers end position:", start, end, payload[start:end])
}
}
@@ -237,6 +237,12 @@ func TestPath(t *testing.T) {
if path = Path(payload); !bytes.Equal(path, []byte("/post")) {
t.Error("Should find path", string(path))
}
payload = []byte("GET /get\r\n\r\nHost: www.w3.org\r\n\r\n")
if path = Path(payload); !bytes.Equal(path, []byte("/get")) {
t.Error("Should find path", string(path))
}
}
func TestSetPath(t *testing.T) {
+1 -1
View File
@@ -244,7 +244,7 @@ func (e *DeviceNotFoundError) Error() string {
devices, _ := pcap.FindAllDevs()
if len(devices) == 0 {
return "Can't get list of network interfaces, ensure that you running Gor as root user or sudo.\nTo run as non-root users see this docs https://github.com/buger/gor/wiki/Running-as-non-root-user"
return "Can't get list of network interfaces, ensure that you running Gor as root user or sudo.\nTo run as non-root users see this docs https://github.com/buger/goreplay/wiki/Running-as-non-root-user"
}
var msg string
+1 -1
View File
@@ -5,7 +5,7 @@ import (
"crypto/sha1"
"encoding/binary"
"encoding/hex"
"github.com/buger/goreplay/proto"
"github.com/buger/gor-pro/proto"
"log"
"net"
"strconv"
+9 -2
View File
@@ -38,10 +38,17 @@ ul {
<h2>Gor PRO releases</h2>
<p>See <a href="https://github.com/buger/gor/releases">releases page on GitHub</a> for changelog</p>
<h3>v0.16.1</h3>
<ul>
<li><a href="./gor_0.16.1_PRO_x64.tar.gz">gor_v0.16.1_PRO_x64.tar.gz</a> - Linux x64</li>
<li><a href="./gor_0.16.1_PRO_mac.tar.gz">gor_v0.16.1_PRO_mac.tar.gz</a> - Mac OS</li>
</ul>
<h3>v0.16.0</h3>
<ul>
<li><a href="./gor_v0.16.0_PRO_x64.tar.gz">gor_v0.16.0_PRO_x64.tar.gz</a> - Linux x64</li>
<li><a href="./gor_v0.16.0_PRO_mac.tar.gz">gor_v0.16.0_PRO_mac.tar.gz</a> - Mac OS</li>
<li><a href="./gor_0.16.0_PRO_x64.tar.gz">gor_v0.16.0_PRO_x64.tar.gz</a> - Linux x64</li>
<li><a href="./gor_0.16.0_PRO_mac.tar.gz">gor_v0.16.0_PRO_mac.tar.gz</a> - Mac OS</li>
</ul>
<h3>v0.15.1</h3>
+13 -3
View File
@@ -38,9 +38,11 @@ type AppSettings struct {
outputStdout bool
outputNull bool
inputTCP MultiOption
outputTCP MultiOption
outputTCPStats bool
inputTCP MultiOption
inputTCPConfig TCPInputConfig
outputTCP MultiOption
outputTCPConfig TCPOutputConfig
outputTCPStats bool
inputFile MultiOption
inputFileLoop bool
@@ -100,7 +102,13 @@ func init() {
flag.BoolVar(&Settings.outputNull, "output-null", false, "Used for testing inputs. Drops all requests.")
flag.Var(&Settings.inputTCP, "input-tcp", "Used for internal communication between Gor instances. Example: \n\t# Receive requests from other Gor instances on 28020 port, and redirect output to staging\n\tgor --input-tcp :28020 --output-http staging.com")
flag.BoolVar(&Settings.inputTCPConfig.secure, "input-tcp-secure", false, "Turn on TLS security. Do not forget to specify certificate and key files.")
flag.StringVar(&Settings.inputTCPConfig.certificatePath, "input-tcp-certificate", "", "Path to PEM encoded certificate file. Used when TLS turned on.")
flag.StringVar(&Settings.inputTCPConfig.keyPath, "input-tcp-certificate-key", "", "Path to PEM encoded certificate key file. Used when TLS turned on.")
flag.Var(&Settings.outputTCP, "output-tcp", "Used for internal communication between Gor instances. Example: \n\t# Listen for requests on 80 port and forward them to other Gor instance on 28020 port\n\tgor --input-raw :80 --output-tcp replay.local:28020")
flag.BoolVar(&Settings.outputTCPConfig.secure, "output-tcp-secure", false, "Use TLS secure connection. --input-file on another end should have TLS turned on as well.")
flag.BoolVar(&Settings.outputTCPStats, "output-tcp-stats", false, "Report TCP output queue stats to console every 5 seconds.")
flag.Var(&Settings.inputFile, "input-file", "Read requests from file: \n\tgor --input-file ./requests.gor --output-http staging.com")
@@ -171,6 +179,8 @@ func init() {
flag.Var(&Settings.modifierConfig.headers, "http-set-header", "Inject additional headers to http reqest:\n\tgor --input-raw :8080 --output-http staging.com --http-set-header 'User-Agent: Gor'")
flag.Var(&Settings.modifierConfig.headers, "output-http-header", "WARNING: `--output-http-header` DEPRECATED, use `--http-set-header` instead")
flag.Var(&Settings.modifierConfig.headerRewrite, "http-rewrite-header", "Rewrite the request header based on a mapping:\n\tgor --input-raw :8080 --output-http staging.com --http-rewrite-header Host: (.*).example.com,$1.beta.example.com")
flag.Var(&Settings.modifierConfig.params, "http-set-param", "Set request url param, if param already exists it will be overwritten:\n\tgor --input-raw :8080 --output-http staging.com --http-set-param api_key=1")
flag.Var(&Settings.modifierConfig.methods, "http-allow-method", "Whitelist of HTTP methods to replay. Anything else will be dropped:\n\tgor --input-raw :8080 --output-http staging.com --http-allow-method GET --http-allow-method OPTIONS")
+1 -1
View File
@@ -46,7 +46,7 @@
},
{
"checksumSHA1": "U2Ydh7vEAKlN0Wq22n1JpefF7uY=",
"origin": "github.com/buger/gor/vendor/github.com/google/gopacket",
"origin": "github.com/buger/goreplay/vendor/github.com/google/gopacket",
"path": "github.com/google/gopacket",
"revision": "b09bf408520f7646e29b7033d9adb00ed779a1c4",
"revisionTime": "2016-05-12T15:06:07Z"