http2: export a field of an internal type for use by net/http

Updates golang/go#22891

Change-Id: Ibde5ce0867a78703a5a4f04fafc3d709ea4cbda3
Reviewed-on: https://go-review.googlesource.com/123656
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
diff --git a/http2/configure_transport.go b/http2/configure_transport.go
index 088d6e2..6356b32 100644
--- a/http2/configure_transport.go
+++ b/http2/configure_transport.go
@@ -57,7 +57,7 @@
 
 // registerHTTPSProtocol calls Transport.RegisterProtocol but
 // converting panics into errors.
-func registerHTTPSProtocol(t *http.Transport, rt http.RoundTripper) (err error) {
+func registerHTTPSProtocol(t *http.Transport, rt noDialH2RoundTripper) (err error) {
 	defer func() {
 		if e := recover(); e != nil {
 			err = fmt.Errorf("%v", e)
@@ -69,10 +69,12 @@
 
 // noDialH2RoundTripper is a RoundTripper which only tries to complete the request
 // if there's already has a cached connection to the host.
-type noDialH2RoundTripper struct{ t *Transport }
+// (The field is exported so it can be accessed via reflect from net/http; tested
+// by TestNoDialH2RoundTripperType)
+type noDialH2RoundTripper struct{ *Transport }
 
 func (rt noDialH2RoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
-	res, err := rt.t.RoundTrip(req)
+	res, err := rt.Transport.RoundTrip(req)
 	if isNoCachedConnError(err) {
 		return nil, http.ErrSkipAltProtocol
 	}
diff --git a/http2/transport_test.go b/http2/transport_test.go
index 23cb820..5b5c076 100644
--- a/http2/transport_test.go
+++ b/http2/transport_test.go
@@ -4161,3 +4161,25 @@
 		t.Error("req2.Body unchanged")
 	}
 }
+
+// Issue 22891: verify that the "https" altproto we register with net/http
+// is a certain type: a struct with one field with our *http2.Transport in it.
+func TestNoDialH2RoundTripperType(t *testing.T) {
+	t1 := new(http.Transport)
+	t2 := new(Transport)
+	rt := noDialH2RoundTripper{t2}
+	if err := registerHTTPSProtocol(t1, rt); err != nil {
+		t.Fatal(err)
+	}
+	rv := reflect.ValueOf(rt)
+	if rv.Type().Kind() != reflect.Struct {
+		t.Fatalf("kind = %v; net/http expects struct", rv.Type().Kind())
+	}
+	if n := rv.Type().NumField(); n != 1 {
+		t.Fatalf("fields = %d; net/http expects 1", n)
+	}
+	v := rv.Field(0)
+	if _, ok := v.Interface().(*Transport); !ok {
+		t.Fatalf("wrong kind %T; want *Transport", v.Interface())
+	}
+}