forked from buger/goreplay
-
Notifications
You must be signed in to change notification settings - Fork 0
/
replay.go
120 lines (98 loc) · 2.33 KB
/
replay.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
// Replay server receive requests objects from Listeners and forward it to given address.
// Basic usage:
//
// gor replay -f http://staging.server
//
//
// Rate limiting
//
// It can be useful if you want forward only part of production traffic, not to overload staging environment. You can specify desired request per second using "|" operator after server address:
//
// # staging.server not get more than 10 requests per second
// gor replay -f "http://staging.server|10"
//
//
// Forward to multiple addresses
//
// Just separate addresses by coma:
// gor replay -f "http://staging.server|10,http://dev.server|20"
//
//
// For more help run:
//
// gor replay -h
//
package replay
import (
"bufio"
"bytes"
"io"
"log"
"net"
"net/http"
)
const bufSize = 4096
// Enable debug logging only if "--verbose" flag passed
func Debug(v ...interface{}) {
if Settings.Verbose {
log.Println(v...)
}
}
func ParseRequest(data []byte) (request *http.Request, err error) {
buf := bytes.NewBuffer(data)
reader := bufio.NewReader(buf)
request, err = http.ReadRequest(reader)
return
}
// Because its sub-program, Run acts as `main`
// Replay server listen to UDP traffic from Listeners
// Each request processed by RequestFactory
func Run() {
listener, err := net.Listen("tcp", Settings.Address())
log.Println("Starting replay server at:", Settings.Address())
if err != nil {
log.Fatal("Can't start:", err)
}
for _, host := range Settings.ForwardedHosts() {
log.Println("Forwarding requests to:", host.Url, "limit:", host.Limit)
}
requestFactory := NewRequestFactory()
for {
conn, err := listener.Accept()
if err != nil {
log.Println("Error while Accept()", err)
continue
}
go handleConnection(conn, requestFactory)
}
}
func handleConnection(conn net.Conn, rf *RequestFactory) error {
defer conn.Close()
var read = true
var response []byte
var buf []byte
buf = make([]byte, bufSize)
for read {
n, err := conn.Read(buf)
switch err {
case io.EOF:
read = false
case nil:
response = append(response, buf[0:n]...)
if n < bufSize {
read = false
}
default:
read = false
}
}
go func() {
if request, err := ParseRequest(response); err != nil {
Debug("Error while parsing request", err, response)
} else {
Debug("Adding request", request)
rf.Add(request)
}
}()
return nil
}