Bläddra i källkod

Recognize https+insecure scheme for symbolization POSTs.

Added a test, verified the test failed before the fix.

This fixes #94.
Alexey Alexandrov 8 år sedan
förälder
incheckning
3fc456e086
2 ändrade filer med 129 tillägg och 1 borttagningar
  1. 108
    0
      internal/driver/driver_test.go
  2. 21
    1
      internal/symbolizer/symbolizer.go

+ 108
- 0
internal/driver/driver_test.go Visa fil

@@ -16,8 +16,17 @@ package driver
16 16
 
17 17
 import (
18 18
 	"bytes"
19
+	"crypto/ecdsa"
20
+	"crypto/elliptic"
21
+	"crypto/rand"
22
+	"crypto/tls"
23
+	"crypto/x509"
24
+	"encoding/pem"
19 25
 	"fmt"
20 26
 	"io/ioutil"
27
+	"math/big"
28
+	"net/http"
29
+	_ "net/http/pprof"
21 30
 	"os"
22 31
 	"regexp"
23 32
 	"runtime"
@@ -329,6 +338,15 @@ func (f testFlags) Parse(func()) []string {
329 338
 	return f.args
330 339
 }
331 340
 
341
+func emptyFlags() testFlags {
342
+	return testFlags{
343
+		bools:   map[string]bool{},
344
+		ints:    map[string]int{},
345
+		floats:  map[string]float64{},
346
+		strings: map[string]string{},
347
+	}
348
+}
349
+
332 350
 func baseFlags() testFlags {
333 351
 	return testFlags{
334 352
 		bools: map[string]bool{
@@ -1023,6 +1041,96 @@ func TestSymbolzAfterMerge(t *testing.T) {
1023 1041
 	}
1024 1042
 }
1025 1043
 
1044
+func TestHttpsInsecure(t *testing.T) {
1045
+	baseVars := pprofVariables
1046
+	pprofVariables = baseVars.makeCopy()
1047
+	defer func() { pprofVariables = baseVars }()
1048
+
1049
+	tlsConfig := &tls.Config{Certificates: []tls.Certificate{selfSignedCert(t)}}
1050
+	donec := make(chan struct{}, 1)
1051
+
1052
+	l, err := tls.Listen("tcp", "localhost:0", tlsConfig)
1053
+	if err != nil {
1054
+		t.Fatalf("net.Listen: got error %v, want no error", err)
1055
+	}
1056
+	defer func() { <-donec }()
1057
+	defer l.Close()
1058
+
1059
+	go func(donec chan<- struct{}) {
1060
+		defer func() { donec <- struct{}{} }()
1061
+		if got, want := http.Serve(l, nil), "use of closed"; !strings.Contains(got.Error(), want) {
1062
+			t.Fatalf("Serve got error %v, want %q", got, want)
1063
+		}
1064
+	}(donec)
1065
+
1066
+	go func() {
1067
+		deadline := time.Now().Add(5 * time.Second)
1068
+		for time.Now().Before(deadline) {
1069
+			// Simulate a hotspot function.
1070
+		}
1071
+	}()
1072
+
1073
+	outputTempFile, err := ioutil.TempFile("", "profile_output")
1074
+	if err != nil {
1075
+		t.Fatalf("Failed to create tempfile: %v", err)
1076
+	}
1077
+	defer os.Remove(outputTempFile.Name())
1078
+	defer outputTempFile.Close()
1079
+
1080
+	f := emptyFlags()
1081
+	o := setDefaults(nil)
1082
+	o.Flagset = &f
1083
+
1084
+	f.args = []string{"https+insecure://" + l.Addr().String() + "/debug/pprof/profile?seconds=5"}
1085
+	addFlags(&f, []string{
1086
+		"top",
1087
+		"symbolize=remote",
1088
+		"output=" + outputTempFile.Name(),
1089
+	})
1090
+
1091
+	if err := PProf(o); err != nil {
1092
+		t.Fatalf("PProf(%v): got error %v, want no error", o, err)
1093
+	}
1094
+
1095
+	b, err := ioutil.ReadFile(outputTempFile.Name())
1096
+	if err != nil {
1097
+		t.Fatalf("ReadFile(%s) got error %v, want no error", outputTempFile.Name(), err)
1098
+	}
1099
+	if got, want := string(b), "TestHttpsInsecure"; !strings.Contains(got, want) {
1100
+		t.Fatalf("Pprof(%v): got %v, want %q substring", o, got, want)
1101
+	}
1102
+}
1103
+
1104
+func selfSignedCert(t *testing.T) tls.Certificate {
1105
+	privKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
1106
+	if err != nil {
1107
+		t.Fatalf("failed to generate private key: %v", err)
1108
+	}
1109
+	b, err := x509.MarshalECPrivateKey(privKey)
1110
+	if err != nil {
1111
+		t.Fatalf("failed to marshal private key: %v", err)
1112
+	}
1113
+	bk := pem.EncodeToMemory(&pem.Block{Type: "EC PRIVATE KEY", Bytes: b})
1114
+
1115
+	tmpl := x509.Certificate{
1116
+		SerialNumber: big.NewInt(1),
1117
+		NotBefore:    time.Now(),
1118
+		NotAfter:     time.Now().Add(10 * time.Minute),
1119
+	}
1120
+
1121
+	b, err = x509.CreateCertificate(rand.Reader, &tmpl, &tmpl, privKey.Public(), privKey)
1122
+	if err != nil {
1123
+		t.Fatalf("failed to create cert: %v", err)
1124
+	}
1125
+	bc := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: b})
1126
+
1127
+	cert, err := tls.X509KeyPair(bc, bk)
1128
+	if err != nil {
1129
+		t.Fatalf("failed to create TLS key pair: %v", err)
1130
+	}
1131
+	return cert
1132
+}
1133
+
1026 1134
 type mockObjTool struct{}
1027 1135
 
1028 1136
 func (*mockObjTool) Open(file string, start, limit, offset uint64) (plugin.ObjFile, error) {

+ 21
- 1
internal/symbolizer/symbolizer.go Visa fil

@@ -18,6 +18,7 @@
18 18
 package symbolizer
19 19
 
20 20
 import (
21
+	"crypto/tls"
21 22
 	"fmt"
22 23
 	"io/ioutil"
23 24
 	"net/http"
@@ -90,7 +91,26 @@ func (s *Symbolizer) Symbolize(mode string, sources plugin.MappingSources, p *pr
90 91
 
91 92
 // postURL issues a POST to a URL over HTTP.
92 93
 func postURL(source, post string) ([]byte, error) {
93
-	resp, err := http.Post(source, "application/octet-stream", strings.NewReader(post))
94
+	url, err := url.Parse(source)
95
+	if err != nil {
96
+		return nil, err
97
+	}
98
+
99
+	var tlsConfig *tls.Config
100
+	if url.Scheme == "https+insecure" {
101
+		tlsConfig = &tls.Config{
102
+			InsecureSkipVerify: true,
103
+		}
104
+		url.Scheme = "https"
105
+		source = url.String()
106
+	}
107
+
108
+	client := &http.Client{
109
+		Transport: &http.Transport{
110
+			TLSClientConfig: tlsConfig,
111
+		},
112
+	}
113
+	resp, err := client.Post(source, "application/octet-stream", strings.NewReader(post))
94 114
 	if err != nil {
95 115
 		return nil, fmt.Errorf("http post %s: %v", source, err)
96 116
 	}