Skip to content

Commit 5ed7d0b

Browse files
Merge pull request #21 from signalsciences/add_server_flavor_support
Add support for 'server_flavor' revproxy config option
2 parents 5a145cd + 3c1b397 commit 5ed7d0b

File tree

6 files changed

+142
-4
lines changed

6 files changed

+142
-4
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
# GoLang Module Release Notes
22

3+
## 1.9.0 2020-10-22
4+
5+
* Added `server_flavor` config option.
6+
37
## 1.8.2 2020-06-15
48

59
* Updated revision for github actions release.

VERSION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
1.8.2
1+
1.9.0

config.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ var (
3333
DefaultTimeout = 100 * time.Millisecond
3434
// DefaultServerIdentifier is the default value
3535
DefaultServerIdentifier = runtime.Version()
36+
// DefaultServerFlavor is the default value
37+
DefaultServerFlavor = ""
3638
)
3739

3840
// HeaderExtractorFunc is a header extraction function
@@ -53,6 +55,7 @@ type ModuleConfig struct {
5355
rpcAddress string
5456
rpcNetwork string
5557
serverIdentifier string
58+
serverFlavor string
5659
timeout time.Duration
5760
}
5861

@@ -72,6 +75,7 @@ func NewModuleConfig(options ...ModuleConfigOption) (*ModuleConfig, error) {
7275
rpcAddress: DefaultRPCAddress,
7376
rpcNetwork: DefaultRPCNetwork,
7477
serverIdentifier: DefaultServerIdentifier,
78+
serverFlavor: DefaultServerFlavor,
7579
timeout: DefaultTimeout,
7680
}
7781
if err := c.SetOptions(options...); err != nil {
@@ -185,6 +189,11 @@ func (c *ModuleConfig) ServerIdentifier() string {
185189
return c.serverIdentifier
186190
}
187191

192+
// ServerFlavor returns the configuration value
193+
func (c *ModuleConfig) ServerFlavor() string {
194+
return c.serverFlavor
195+
}
196+
188197
// Timeout returns the configuration value
189198
func (c *ModuleConfig) Timeout() time.Duration {
190199
return c.timeout
@@ -335,6 +344,15 @@ func ServerIdentifier(id string) ModuleConfigOption {
335344
}
336345
}
337346

347+
// ServerFlavor is a function argument that sets the server
348+
// flavor for custom setups using revproxy.
349+
func ServerFlavor(serverFlavor string) ModuleConfigOption {
350+
return func(c *ModuleConfig) error {
351+
c.serverFlavor = serverFlavor
352+
return nil
353+
}
354+
}
355+
338356
// FromModuleConfig allow cloning the config
339357
func FromModuleConfig(mcfg *ModuleConfig) ModuleConfigOption {
340358
return func(c *ModuleConfig) error {

module.go

Lines changed: 49 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ func NewModule(h http.Handler, options ...ModuleConfigOption) (*Module, error) {
6363
in := RPCMsgIn{
6464
ModuleVersion: m.config.ModuleIdentifier(),
6565
ServerVersion: m.config.ServerIdentifier(),
66-
ServerFlavor: "",
66+
ServerFlavor: m.config.ServerFlavor(),
6767
Timestamp: now.Unix(),
6868
NowMillis: now.UnixNano() / 1e6,
6969
}
@@ -225,7 +225,7 @@ func (m *Module) inspectorPreRequest(req *http.Request) (inspin2 RPCMsgIn2, out
225225
req.Body = ioutil.NopCloser(bytes.NewBuffer(reqbody))
226226
}
227227

228-
inspin := NewRPCMsgIn(req, reqbody, -1, -1, -1, m.config.ModuleIdentifier(), m.config.ServerIdentifier())
228+
inspin := NewRPCMsgInWithModuleConfig(m.config, req, reqbody)
229229
m.extractHeaders(req, inspin)
230230

231231
if m.config.Debug() {
@@ -371,6 +371,53 @@ func NewRPCMsgIn(r *http.Request, postbody []byte, code int, size int64, dur tim
371371
}
372372
}
373373

374+
// NewRPCMsgInWithModuleConfig creates a message from a ModuleConfig object
375+
// End-users of the golang module never need to use this
376+
// directly and it is only exposed for performance testing
377+
func NewRPCMsgInWithModuleConfig(mcfg *ModuleConfig, r *http.Request, postbody []byte) *RPCMsgIn {
378+
379+
now := time.Now()
380+
381+
// assemble a message to send to inspector
382+
tlsProtocol := ""
383+
tlsCipher := ""
384+
scheme := "http"
385+
if r.TLS != nil {
386+
// convert golang/spec integers into something human readable
387+
scheme = "https"
388+
tlsProtocol = tlstext.Version(r.TLS.Version)
389+
tlsCipher = tlstext.CipherSuite(r.TLS.CipherSuite)
390+
}
391+
392+
// golang removes Host header from req.Header map and
393+
// promotes it to r.Host field. Add it back as the first header.
394+
hin := convertHeaders(r.Header)
395+
if len(r.Host) > 0 {
396+
hin = append([][2]string{{"Host", r.Host}}, hin...)
397+
}
398+
399+
return &RPCMsgIn{
400+
ModuleVersion: mcfg.ModuleIdentifier(),
401+
ServerVersion: mcfg.ServerIdentifier(),
402+
ServerFlavor: mcfg.ServerFlavor(),
403+
ServerName: r.Host,
404+
Timestamp: now.Unix(),
405+
NowMillis: now.UnixNano() / 1e6,
406+
RemoteAddr: stripPort(r.RemoteAddr),
407+
Method: r.Method,
408+
Scheme: scheme,
409+
URI: r.RequestURI,
410+
Protocol: r.Proto,
411+
TLSProtocol: tlsProtocol,
412+
TLSCipher: tlsCipher,
413+
ResponseCode: -1,
414+
ResponseMillis: 0,
415+
ResponseSize: -1,
416+
PostBody: string(postbody),
417+
HeadersIn: hin,
418+
}
419+
}
420+
374421
// stripPort removes any port from an address (e.g., the client port from the RemoteAddr)
375422
func stripPort(ipdots string) string {
376423
host, _, err := net.SplitHostPort(ipdots)

module_test.go

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,75 @@ import (
1515
"time"
1616
)
1717

18+
func TestNewRPCMsgInWithModuleConfigFromRequest(t *testing.T) {
19+
20+
c, err := NewModuleConfig(
21+
AllowUnknownContentLength(true),
22+
ServerFlavor("SugarAndSpice"),
23+
AltResponseCodes(403),
24+
AnomalyDuration(10*time.Second),
25+
AnomalySize(8192),
26+
CustomInspector(&RPCInspector{}, func(_ *http.Request) bool { return true }, func(_ *http.Request) {}),
27+
CustomHeaderExtractor(func(_ *http.Request) (http.Header, error) { return nil, nil }),
28+
Debug(true),
29+
MaxContentLength(500000),
30+
Socket("tcp", "0.0.0.0:1234"),
31+
Timeout(10*time.Millisecond),
32+
)
33+
if err != nil {
34+
t.Fatalf("Failed to create module config: %s", err)
35+
}
36+
37+
b := bytes.Buffer{}
38+
b.WriteString("test")
39+
r, err := http.NewRequest("GET", "http://localhost/", &b)
40+
if err != nil {
41+
t.Fatal(err)
42+
}
43+
r.RemoteAddr = "127.0.0.1"
44+
r.Header.Add("If-None-Match", `W/"wyzzy"`)
45+
r.RequestURI = "http://localhost/"
46+
r.TLS = &tls.ConnectionState{}
47+
48+
want := RPCMsgIn{
49+
ServerName: "localhost",
50+
ServerFlavor: "SugarAndSpice",
51+
Method: "GET",
52+
Scheme: "https",
53+
URI: "http://localhost/",
54+
Protocol: "HTTP/1.1",
55+
RemoteAddr: "127.0.0.1",
56+
HeadersIn: [][2]string{{"Host", "localhost"}, {"If-None-Match", `W/"wyzzy"`}},
57+
}
58+
eq := func(got, want RPCMsgIn) (ne string, equal bool) {
59+
switch {
60+
case got.ServerName != want.ServerName:
61+
return "ServerHostname", false
62+
case got.Method != want.Method:
63+
return "Method", false
64+
case got.Scheme != want.Scheme:
65+
return "Scheme", false
66+
case got.URI != want.URI:
67+
return "URI", false
68+
case got.Protocol != want.Protocol:
69+
return "Protocol", false
70+
case got.RemoteAddr != want.RemoteAddr:
71+
return "RemoteAddr", false
72+
case !reflect.DeepEqual(got.HeadersIn, want.HeadersIn):
73+
return "HeadersIn", false
74+
case got.ServerFlavor != want.ServerFlavor:
75+
return "ServerFlavor", false
76+
default:
77+
return "", true
78+
}
79+
}
80+
81+
got := NewRPCMsgInWithModuleConfig(c, r, nil)
82+
if ne, equal := eq(*got, want); !equal {
83+
t.Errorf("NewRPCMsgInWithModuleConfig: incorrect %q", ne)
84+
}
85+
}
86+
1887
func TestNewRPCMsgFromRequest(t *testing.T) {
1988
b := bytes.Buffer{}
2089
b.WriteString("test")

version.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
package sigsci
22

3-
const version = "1.8.0"
3+
const version = "1.9.0"

0 commit comments

Comments
 (0)