浏览代码

Recognize (again) https+insecure scheme for symbolization POSTs. (#121)

* Recognize (again) https+insecure scheme for symbolization POSTs.

This reverts the revert of #111 relaxing the test to make it pass as the
issue reported in #111 is caused by unrelated #120.

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

This fixes #94.

* Fix the staticcheck failure.
Alexey Alexandrov 8 年前
父节点
当前提交
696c91bc6d
共有 2 个文件被更改,包括 132 次插入1 次删除
  1. 111
    0
      internal/driver/driver_test.go
  2. 21
    1
      internal/symbolizer/symbolizer.go

+ 111
- 0
internal/driver/driver_test.go 查看文件

@@ -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{
@@ -1020,6 +1038,99 @@ func TestSymbolzAfterMerge(t *testing.T) {
1020 1038
 	}
1021 1039
 }
1022 1040
 
1041
+func TestHttpsInsecure(t *testing.T) {
1042
+	baseVars := pprofVariables
1043
+	pprofVariables = baseVars.makeCopy()
1044
+	defer func() { pprofVariables = baseVars }()
1045
+
1046
+	tlsConfig := &tls.Config{Certificates: []tls.Certificate{selfSignedCert(t)}}
1047
+
1048
+	l, err := tls.Listen("tcp", "localhost:0", tlsConfig)
1049
+	if err != nil {
1050
+		t.Fatalf("net.Listen: got error %v, want no error", err)
1051
+	}
1052
+
1053
+	donec := make(chan error, 1)
1054
+	go func(donec chan<- error) {
1055
+		donec <- http.Serve(l, nil)
1056
+	}(donec)
1057
+	defer func() {
1058
+		if got, want := <-donec, "use of closed"; !strings.Contains(got.Error(), want) {
1059
+			t.Fatalf("Serve got error %v, want %q", got, want)
1060
+		}
1061
+	}()
1062
+	defer l.Close()
1063
+
1064
+	go func() {
1065
+		deadline := time.Now().Add(5 * time.Second)
1066
+		for time.Now().Before(deadline) {
1067
+			// Simulate a hotspot function.
1068
+		}
1069
+	}()
1070
+
1071
+	outputTempFile, err := ioutil.TempFile("", "profile_output")
1072
+	if err != nil {
1073
+		t.Fatalf("Failed to create tempfile: %v", err)
1074
+	}
1075
+	defer os.Remove(outputTempFile.Name())
1076
+	defer outputTempFile.Close()
1077
+
1078
+	f := emptyFlags()
1079
+	o := setDefaults(nil)
1080
+	o.Flagset = &f
1081
+
1082
+	f.args = []string{"https+insecure://" + l.Addr().String() + "/debug/pprof/profile?seconds=5"}
1083
+	addFlags(&f, []string{
1084
+		"top",
1085
+		"symbolize=remote",
1086
+		"output=" + outputTempFile.Name(),
1087
+	})
1088
+
1089
+	if err := PProf(o); err != nil {
1090
+		t.Fatalf("PProf(%v): got error %v, want no error", o, err)
1091
+	}
1092
+
1093
+	b, err := ioutil.ReadFile(outputTempFile.Name())
1094
+	if err != nil {
1095
+		t.Fatalf("ReadFile(%s) got error %v, want no error", outputTempFile.Name(), err)
1096
+	}
1097
+	// TODO(aalexand): Fix to reqiure "TestHttpsInsecure" in the output once #120
1098
+	// is fixed which causes symbolization issues on OSX with Go 1.8.
1099
+	if got, want := string(b), "Showing nodes accounting"; !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
+
1023 1134
 type mockObjTool struct{}
1024 1135
 
1025 1136
 func (*mockObjTool) Open(file string, start, limit, offset uint64) (plugin.ObjFile, error) {

+ 21
- 1
internal/symbolizer/symbolizer.go 查看文件

@@ -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
 	}