http2: remove support for Go 1.8 and earlier

Go's policy is to only support the past two releases (which is
currently Go 1.11 and Go 1.10). But because App Engine was stuck on Go
1.6 and Go 1.8 for so long, we kept kinda supporting Go 1.6 anyway,
even though we didn't actively test it with any CI system.

But that led to code getting disgusting and full of too many
+build-tagged files and indirection, as this change shows.

So, remove Go 1.8, Go 1.7, and Go 1.6 support. We still "support" Go
1.9 for now, even though it's also not actively tested.

Fixes golang/go#26302

Change-Id: I4aa5793173e50ffcd67be52a464492ca48fc9a23
Reviewed-on: https://go-review.googlesource.com/c/145677
Reviewed-by: Dmitri Shuralyov <dmitshur@golang.org>
diff --git a/http2/configure_transport.go b/http2/configure_transport.go
deleted file mode 100644
index 6356b32..0000000
--- a/http2/configure_transport.go
+++ /dev/null
@@ -1,82 +0,0 @@
-// Copyright 2015 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// +build go1.6
-
-package http2
-
-import (
-	"crypto/tls"
-	"fmt"
-	"net/http"
-)
-
-func configureTransport(t1 *http.Transport) (*Transport, error) {
-	connPool := new(clientConnPool)
-	t2 := &Transport{
-		ConnPool: noDialClientConnPool{connPool},
-		t1:       t1,
-	}
-	connPool.t = t2
-	if err := registerHTTPSProtocol(t1, noDialH2RoundTripper{t2}); err != nil {
-		return nil, err
-	}
-	if t1.TLSClientConfig == nil {
-		t1.TLSClientConfig = new(tls.Config)
-	}
-	if !strSliceContains(t1.TLSClientConfig.NextProtos, "h2") {
-		t1.TLSClientConfig.NextProtos = append([]string{"h2"}, t1.TLSClientConfig.NextProtos...)
-	}
-	if !strSliceContains(t1.TLSClientConfig.NextProtos, "http/1.1") {
-		t1.TLSClientConfig.NextProtos = append(t1.TLSClientConfig.NextProtos, "http/1.1")
-	}
-	upgradeFn := func(authority string, c *tls.Conn) http.RoundTripper {
-		addr := authorityAddr("https", authority)
-		if used, err := connPool.addConnIfNeeded(addr, t2, c); err != nil {
-			go c.Close()
-			return erringRoundTripper{err}
-		} else if !used {
-			// Turns out we don't need this c.
-			// For example, two goroutines made requests to the same host
-			// at the same time, both kicking off TCP dials. (since protocol
-			// was unknown)
-			go c.Close()
-		}
-		return t2
-	}
-	if m := t1.TLSNextProto; len(m) == 0 {
-		t1.TLSNextProto = map[string]func(string, *tls.Conn) http.RoundTripper{
-			"h2": upgradeFn,
-		}
-	} else {
-		m["h2"] = upgradeFn
-	}
-	return t2, nil
-}
-
-// registerHTTPSProtocol calls Transport.RegisterProtocol but
-// converting panics into errors.
-func registerHTTPSProtocol(t *http.Transport, rt noDialH2RoundTripper) (err error) {
-	defer func() {
-		if e := recover(); e != nil {
-			err = fmt.Errorf("%v", e)
-		}
-	}()
-	t.RegisterProtocol("https", rt)
-	return nil
-}
-
-// noDialH2RoundTripper is a RoundTripper which only tries to complete the request
-// if there's already has a cached connection to the host.
-// (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.Transport.RoundTrip(req)
-	if isNoCachedConnError(err) {
-		return nil, http.ErrSkipAltProtocol
-	}
-	return res, err
-}
diff --git a/http2/databuffer_test.go b/http2/databuffer_test.go
index 028e12e..32cd5f3 100644
--- a/http2/databuffer_test.go
+++ b/http2/databuffer_test.go
@@ -2,8 +2,6 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build go1.7
-
 package http2
 
 import (
diff --git a/http2/go111.go b/http2/go111.go
index 9749dc0..3a13101 100644
--- a/http2/go111.go
+++ b/http2/go111.go
@@ -6,19 +6,22 @@
 
 package http2
 
-import "net/textproto"
+import (
+	"net/http/httptrace"
+	"net/textproto"
+)
 
-func traceHasWroteHeaderField(trace *clientTrace) bool {
+func traceHasWroteHeaderField(trace *httptrace.ClientTrace) bool {
 	return trace != nil && trace.WroteHeaderField != nil
 }
 
-func traceWroteHeaderField(trace *clientTrace, k, v string) {
+func traceWroteHeaderField(trace *httptrace.ClientTrace, k, v string) {
 	if trace != nil && trace.WroteHeaderField != nil {
 		trace.WroteHeaderField(k, []string{v})
 	}
 }
 
-func traceGot1xxResponseFunc(trace *clientTrace) func(int, textproto.MIMEHeader) error {
+func traceGot1xxResponseFunc(trace *httptrace.ClientTrace) func(int, textproto.MIMEHeader) error {
 	if trace != nil {
 		return trace.Got1xxResponse
 	}
diff --git a/http2/go16.go b/http2/go16.go
deleted file mode 100644
index 00b2e9e..0000000
--- a/http2/go16.go
+++ /dev/null
@@ -1,16 +0,0 @@
-// Copyright 2016 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// +build go1.6
-
-package http2
-
-import (
-	"net/http"
-	"time"
-)
-
-func transportExpectContinueTimeout(t1 *http.Transport) time.Duration {
-	return t1.ExpectContinueTimeout
-}
diff --git a/http2/go17.go b/http2/go17.go
deleted file mode 100644
index d957b7b..0000000
--- a/http2/go17.go
+++ /dev/null
@@ -1,121 +0,0 @@
-// Copyright 2016 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// +build go1.7
-
-package http2
-
-import (
-	"context"
-	"net"
-	"net/http"
-	"net/http/httptrace"
-	"time"
-)
-
-type contextContext interface {
-	context.Context
-}
-
-var errCanceled = context.Canceled
-
-func serverConnBaseContext(c net.Conn, opts *ServeConnOpts) (ctx contextContext, cancel func()) {
-	ctx, cancel = context.WithCancel(context.Background())
-	ctx = context.WithValue(ctx, http.LocalAddrContextKey, c.LocalAddr())
-	if hs := opts.baseConfig(); hs != nil {
-		ctx = context.WithValue(ctx, http.ServerContextKey, hs)
-	}
-	return
-}
-
-func contextWithCancel(ctx contextContext) (_ contextContext, cancel func()) {
-	return context.WithCancel(ctx)
-}
-
-func requestWithContext(req *http.Request, ctx contextContext) *http.Request {
-	return req.WithContext(ctx)
-}
-
-type clientTrace httptrace.ClientTrace
-
-func reqContext(r *http.Request) context.Context { return r.Context() }
-
-func (t *Transport) idleConnTimeout() time.Duration {
-	if t.t1 != nil {
-		return t.t1.IdleConnTimeout
-	}
-	return 0
-}
-
-func setResponseUncompressed(res *http.Response) { res.Uncompressed = true }
-
-func traceGetConn(req *http.Request, hostPort string) {
-	trace := httptrace.ContextClientTrace(req.Context())
-	if trace == nil || trace.GetConn == nil {
-		return
-	}
-	trace.GetConn(hostPort)
-}
-
-func traceGotConn(req *http.Request, cc *ClientConn) {
-	trace := httptrace.ContextClientTrace(req.Context())
-	if trace == nil || trace.GotConn == nil {
-		return
-	}
-	ci := httptrace.GotConnInfo{Conn: cc.tconn}
-	cc.mu.Lock()
-	ci.Reused = cc.nextStreamID > 1
-	ci.WasIdle = len(cc.streams) == 0 && ci.Reused
-	if ci.WasIdle && !cc.lastActive.IsZero() {
-		ci.IdleTime = time.Now().Sub(cc.lastActive)
-	}
-	cc.mu.Unlock()
-
-	trace.GotConn(ci)
-}
-
-func traceWroteHeaders(trace *clientTrace) {
-	if trace != nil && trace.WroteHeaders != nil {
-		trace.WroteHeaders()
-	}
-}
-
-func traceGot100Continue(trace *clientTrace) {
-	if trace != nil && trace.Got100Continue != nil {
-		trace.Got100Continue()
-	}
-}
-
-func traceWait100Continue(trace *clientTrace) {
-	if trace != nil && trace.Wait100Continue != nil {
-		trace.Wait100Continue()
-	}
-}
-
-func traceWroteRequest(trace *clientTrace, err error) {
-	if trace != nil && trace.WroteRequest != nil {
-		trace.WroteRequest(httptrace.WroteRequestInfo{Err: err})
-	}
-}
-
-func traceFirstResponseByte(trace *clientTrace) {
-	if trace != nil && trace.GotFirstResponseByte != nil {
-		trace.GotFirstResponseByte()
-	}
-}
-
-func requestTrace(req *http.Request) *clientTrace {
-	trace := httptrace.ContextClientTrace(req.Context())
-	return (*clientTrace)(trace)
-}
-
-// Ping sends a PING frame to the server and waits for the ack.
-func (cc *ClientConn) Ping(ctx context.Context) error {
-	return cc.ping(ctx)
-}
-
-// Shutdown gracefully closes the client connection, waiting for running streams to complete.
-func (cc *ClientConn) Shutdown(ctx context.Context) error {
-	return cc.shutdown(ctx)
-}
diff --git a/http2/go17_not18.go b/http2/go17_not18.go
deleted file mode 100644
index b4c52ec..0000000
--- a/http2/go17_not18.go
+++ /dev/null
@@ -1,36 +0,0 @@
-// Copyright 2016 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// +build go1.7,!go1.8
-
-package http2
-
-import "crypto/tls"
-
-// temporary copy of Go 1.7's private tls.Config.clone:
-func cloneTLSConfig(c *tls.Config) *tls.Config {
-	return &tls.Config{
-		Rand:                        c.Rand,
-		Time:                        c.Time,
-		Certificates:                c.Certificates,
-		NameToCertificate:           c.NameToCertificate,
-		GetCertificate:              c.GetCertificate,
-		RootCAs:                     c.RootCAs,
-		NextProtos:                  c.NextProtos,
-		ServerName:                  c.ServerName,
-		ClientAuth:                  c.ClientAuth,
-		ClientCAs:                   c.ClientCAs,
-		InsecureSkipVerify:          c.InsecureSkipVerify,
-		CipherSuites:                c.CipherSuites,
-		PreferServerCipherSuites:    c.PreferServerCipherSuites,
-		SessionTicketsDisabled:      c.SessionTicketsDisabled,
-		SessionTicketKey:            c.SessionTicketKey,
-		ClientSessionCache:          c.ClientSessionCache,
-		MinVersion:                  c.MinVersion,
-		MaxVersion:                  c.MaxVersion,
-		CurvePreferences:            c.CurvePreferences,
-		DynamicRecordSizingDisabled: c.DynamicRecordSizingDisabled,
-		Renegotiation:               c.Renegotiation,
-	}
-}
diff --git a/http2/go18.go b/http2/go18.go
deleted file mode 100644
index 4f30d22..0000000
--- a/http2/go18.go
+++ /dev/null
@@ -1,56 +0,0 @@
-// Copyright 2015 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// +build go1.8
-
-package http2
-
-import (
-	"crypto/tls"
-	"io"
-	"net/http"
-)
-
-func cloneTLSConfig(c *tls.Config) *tls.Config {
-	c2 := c.Clone()
-	c2.GetClientCertificate = c.GetClientCertificate // golang.org/issue/19264
-	return c2
-}
-
-var _ http.Pusher = (*responseWriter)(nil)
-
-// Push implements http.Pusher.
-func (w *responseWriter) Push(target string, opts *http.PushOptions) error {
-	internalOpts := pushOptions{}
-	if opts != nil {
-		internalOpts.Method = opts.Method
-		internalOpts.Header = opts.Header
-	}
-	return w.push(target, internalOpts)
-}
-
-func configureServer18(h1 *http.Server, h2 *Server) error {
-	if h2.IdleTimeout == 0 {
-		if h1.IdleTimeout != 0 {
-			h2.IdleTimeout = h1.IdleTimeout
-		} else {
-			h2.IdleTimeout = h1.ReadTimeout
-		}
-	}
-	return nil
-}
-
-func shouldLogPanic(panicValue interface{}) bool {
-	return panicValue != nil && panicValue != http.ErrAbortHandler
-}
-
-func reqGetBody(req *http.Request) func() (io.ReadCloser, error) {
-	return req.GetBody
-}
-
-func reqBodyIsNoBody(body io.ReadCloser) bool {
-	return body == http.NoBody
-}
-
-func go18httpNoBody() io.ReadCloser { return http.NoBody } // for tests only
diff --git a/http2/go18_test.go b/http2/go18_test.go
deleted file mode 100644
index 30e3b03..0000000
--- a/http2/go18_test.go
+++ /dev/null
@@ -1,79 +0,0 @@
-// Copyright 2016 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// +build go1.8
-
-package http2
-
-import (
-	"crypto/tls"
-	"net/http"
-	"testing"
-	"time"
-)
-
-// Tests that http2.Server.IdleTimeout is initialized from
-// http.Server.{Idle,Read}Timeout. http.Server.IdleTimeout was
-// added in Go 1.8.
-func TestConfigureServerIdleTimeout_Go18(t *testing.T) {
-	const timeout = 5 * time.Second
-	const notThisOne = 1 * time.Second
-
-	// With a zero http2.Server, verify that it copies IdleTimeout:
-	{
-		s1 := &http.Server{
-			IdleTimeout: timeout,
-			ReadTimeout: notThisOne,
-		}
-		s2 := &Server{}
-		if err := ConfigureServer(s1, s2); err != nil {
-			t.Fatal(err)
-		}
-		if s2.IdleTimeout != timeout {
-			t.Errorf("s2.IdleTimeout = %v; want %v", s2.IdleTimeout, timeout)
-		}
-	}
-
-	// And that it falls back to ReadTimeout:
-	{
-		s1 := &http.Server{
-			ReadTimeout: timeout,
-		}
-		s2 := &Server{}
-		if err := ConfigureServer(s1, s2); err != nil {
-			t.Fatal(err)
-		}
-		if s2.IdleTimeout != timeout {
-			t.Errorf("s2.IdleTimeout = %v; want %v", s2.IdleTimeout, timeout)
-		}
-	}
-
-	// Verify that s1's IdleTimeout doesn't overwrite an existing setting:
-	{
-		s1 := &http.Server{
-			IdleTimeout: notThisOne,
-		}
-		s2 := &Server{
-			IdleTimeout: timeout,
-		}
-		if err := ConfigureServer(s1, s2); err != nil {
-			t.Fatal(err)
-		}
-		if s2.IdleTimeout != timeout {
-			t.Errorf("s2.IdleTimeout = %v; want %v", s2.IdleTimeout, timeout)
-		}
-	}
-}
-
-func TestCertClone(t *testing.T) {
-	c := &tls.Config{
-		GetClientCertificate: func(*tls.CertificateRequestInfo) (*tls.Certificate, error) {
-			panic("shouldn't be called")
-		},
-	}
-	c2 := cloneTLSConfig(c)
-	if c2.GetClientCertificate == nil {
-		t.Error("GetClientCertificate is nil")
-	}
-}
diff --git a/http2/go19.go b/http2/go19.go
deleted file mode 100644
index 38124ba..0000000
--- a/http2/go19.go
+++ /dev/null
@@ -1,16 +0,0 @@
-// Copyright 2015 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// +build go1.9
-
-package http2
-
-import (
-	"net/http"
-)
-
-func configureServer19(s *http.Server, conf *Server) error {
-	s.RegisterOnShutdown(conf.state.startGracefulShutdown)
-	return nil
-}
diff --git a/http2/go19_test.go b/http2/go19_test.go
deleted file mode 100644
index 22b0006..0000000
--- a/http2/go19_test.go
+++ /dev/null
@@ -1,59 +0,0 @@
-// Copyright 2017 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// +build go1.9
-
-package http2
-
-import (
-	"context"
-	"net/http"
-	"reflect"
-	"testing"
-	"time"
-)
-
-func TestServerGracefulShutdown(t *testing.T) {
-	var st *serverTester
-	handlerDone := make(chan struct{})
-	st = newServerTester(t, func(w http.ResponseWriter, r *http.Request) {
-		defer close(handlerDone)
-		go st.ts.Config.Shutdown(context.Background())
-
-		ga := st.wantGoAway()
-		if ga.ErrCode != ErrCodeNo {
-			t.Errorf("GOAWAY error = %v; want ErrCodeNo", ga.ErrCode)
-		}
-		if ga.LastStreamID != 1 {
-			t.Errorf("GOAWAY LastStreamID = %v; want 1", ga.LastStreamID)
-		}
-
-		w.Header().Set("x-foo", "bar")
-	})
-	defer st.Close()
-
-	st.greet()
-	st.bodylessReq1()
-
-	select {
-	case <-handlerDone:
-	case <-time.After(5 * time.Second):
-		t.Fatalf("server did not shutdown?")
-	}
-	hf := st.wantHeaders()
-	goth := st.decodeHeader(hf.HeaderBlockFragment())
-	wanth := [][2]string{
-		{":status", "200"},
-		{"x-foo", "bar"},
-		{"content-length", "0"},
-	}
-	if !reflect.DeepEqual(goth, wanth) {
-		t.Errorf("Got headers %v; want %v", goth, wanth)
-	}
-
-	n, err := st.cc.Read([]byte{0})
-	if n != 0 || err == nil {
-		t.Errorf("Read = %v, %v; want 0, non-nil", n, err)
-	}
-}
diff --git a/http2/http2_test.go b/http2/http2_test.go
index 667db48..dda6743 100644
--- a/http2/http2_test.go
+++ b/http2/http2_test.go
@@ -225,3 +225,56 @@
 	}
 	return err
 }
+
+// Tests that http2.Server.IdleTimeout is initialized from
+// http.Server.{Idle,Read}Timeout. http.Server.IdleTimeout was
+// added in Go 1.8.
+func TestConfigureServerIdleTimeout_Go18(t *testing.T) {
+	const timeout = 5 * time.Second
+	const notThisOne = 1 * time.Second
+
+	// With a zero http2.Server, verify that it copies IdleTimeout:
+	{
+		s1 := &http.Server{
+			IdleTimeout: timeout,
+			ReadTimeout: notThisOne,
+		}
+		s2 := &Server{}
+		if err := ConfigureServer(s1, s2); err != nil {
+			t.Fatal(err)
+		}
+		if s2.IdleTimeout != timeout {
+			t.Errorf("s2.IdleTimeout = %v; want %v", s2.IdleTimeout, timeout)
+		}
+	}
+
+	// And that it falls back to ReadTimeout:
+	{
+		s1 := &http.Server{
+			ReadTimeout: timeout,
+		}
+		s2 := &Server{}
+		if err := ConfigureServer(s1, s2); err != nil {
+			t.Fatal(err)
+		}
+		if s2.IdleTimeout != timeout {
+			t.Errorf("s2.IdleTimeout = %v; want %v", s2.IdleTimeout, timeout)
+		}
+	}
+
+	// Verify that s1's IdleTimeout doesn't overwrite an existing setting:
+	{
+		s1 := &http.Server{
+			IdleTimeout: notThisOne,
+		}
+		s2 := &Server{
+			IdleTimeout: timeout,
+		}
+		if err := ConfigureServer(s1, s2); err != nil {
+			t.Fatal(err)
+		}
+		if s2.IdleTimeout != timeout {
+			t.Errorf("s2.IdleTimeout = %v; want %v", s2.IdleTimeout, timeout)
+		}
+	}
+}
diff --git a/http2/not_go111.go b/http2/not_go111.go
index 0df34e6..161bca7 100644
--- a/http2/not_go111.go
+++ b/http2/not_go111.go
@@ -6,12 +6,15 @@
 
 package http2
 
-import "net/textproto"
+import (
+	"net/http/httptrace"
+	"net/textproto"
+)
 
-func traceHasWroteHeaderField(trace *clientTrace) bool { return false }
+func traceHasWroteHeaderField(trace *httptrace.ClientTrace) bool { return false }
 
-func traceWroteHeaderField(trace *clientTrace, k, v string) {}
+func traceWroteHeaderField(trace *httptrace.ClientTrace, k, v string) {}
 
-func traceGot1xxResponseFunc(trace *clientTrace) func(int, textproto.MIMEHeader) error {
+func traceGot1xxResponseFunc(trace *httptrace.ClientTrace) func(int, textproto.MIMEHeader) error {
 	return nil
 }
diff --git a/http2/not_go16.go b/http2/not_go16.go
deleted file mode 100644
index 508cebc..0000000
--- a/http2/not_go16.go
+++ /dev/null
@@ -1,21 +0,0 @@
-// Copyright 2015 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// +build !go1.6
-
-package http2
-
-import (
-	"net/http"
-	"time"
-)
-
-func configureTransport(t1 *http.Transport) (*Transport, error) {
-	return nil, errTransportVersion
-}
-
-func transportExpectContinueTimeout(t1 *http.Transport) time.Duration {
-	return 0
-
-}
diff --git a/http2/not_go17.go b/http2/not_go17.go
deleted file mode 100644
index 7ffb250..0000000
--- a/http2/not_go17.go
+++ /dev/null
@@ -1,95 +0,0 @@
-// Copyright 2016 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// +build !go1.7
-
-package http2
-
-import (
-	"crypto/tls"
-	"errors"
-	"net"
-	"net/http"
-	"time"
-)
-
-type contextContext interface {
-	Done() <-chan struct{}
-	Err() error
-}
-
-var errCanceled = errors.New("canceled")
-
-type fakeContext struct{}
-
-func (fakeContext) Done() <-chan struct{} { return nil }
-func (fakeContext) Err() error            { panic("should not be called") }
-
-func reqContext(r *http.Request) fakeContext {
-	return fakeContext{}
-}
-
-func setResponseUncompressed(res *http.Response) {
-	// Nothing.
-}
-
-type clientTrace struct{}
-
-func requestTrace(*http.Request) *clientTrace { return nil }
-func traceGetConn(*http.Request, string)      {}
-func traceGotConn(*http.Request, *ClientConn) {}
-func traceFirstResponseByte(*clientTrace)     {}
-func traceWroteHeaders(*clientTrace)          {}
-func traceWroteRequest(*clientTrace, error)   {}
-func traceGot100Continue(trace *clientTrace)  {}
-func traceWait100Continue(trace *clientTrace) {}
-
-func nop() {}
-
-func serverConnBaseContext(c net.Conn, opts *ServeConnOpts) (ctx contextContext, cancel func()) {
-	return nil, nop
-}
-
-func contextWithCancel(ctx contextContext) (_ contextContext, cancel func()) {
-	return ctx, nop
-}
-
-func requestWithContext(req *http.Request, ctx contextContext) *http.Request {
-	return req
-}
-
-// temporary copy of Go 1.6's private tls.Config.clone:
-func cloneTLSConfig(c *tls.Config) *tls.Config {
-	return &tls.Config{
-		Rand:                     c.Rand,
-		Time:                     c.Time,
-		Certificates:             c.Certificates,
-		NameToCertificate:        c.NameToCertificate,
-		GetCertificate:           c.GetCertificate,
-		RootCAs:                  c.RootCAs,
-		NextProtos:               c.NextProtos,
-		ServerName:               c.ServerName,
-		ClientAuth:               c.ClientAuth,
-		ClientCAs:                c.ClientCAs,
-		InsecureSkipVerify:       c.InsecureSkipVerify,
-		CipherSuites:             c.CipherSuites,
-		PreferServerCipherSuites: c.PreferServerCipherSuites,
-		SessionTicketsDisabled:   c.SessionTicketsDisabled,
-		SessionTicketKey:         c.SessionTicketKey,
-		ClientSessionCache:       c.ClientSessionCache,
-		MinVersion:               c.MinVersion,
-		MaxVersion:               c.MaxVersion,
-		CurvePreferences:         c.CurvePreferences,
-	}
-}
-
-func (cc *ClientConn) Ping(ctx contextContext) error {
-	return cc.ping(ctx)
-}
-
-func (cc *ClientConn) Shutdown(ctx contextContext) error {
-	return cc.shutdown(ctx)
-}
-
-func (t *Transport) idleConnTimeout() time.Duration { return 0 }
diff --git a/http2/not_go18.go b/http2/not_go18.go
deleted file mode 100644
index 6f8d3f8..0000000
--- a/http2/not_go18.go
+++ /dev/null
@@ -1,29 +0,0 @@
-// Copyright 2016 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// +build !go1.8
-
-package http2
-
-import (
-	"io"
-	"net/http"
-)
-
-func configureServer18(h1 *http.Server, h2 *Server) error {
-	// No IdleTimeout to sync prior to Go 1.8.
-	return nil
-}
-
-func shouldLogPanic(panicValue interface{}) bool {
-	return panicValue != nil
-}
-
-func reqGetBody(req *http.Request) func() (io.ReadCloser, error) {
-	return nil
-}
-
-func reqBodyIsNoBody(io.ReadCloser) bool { return false }
-
-func go18httpNoBody() io.ReadCloser { return nil } // for tests only
diff --git a/http2/not_go19.go b/http2/not_go19.go
deleted file mode 100644
index 5ae0772..0000000
--- a/http2/not_go19.go
+++ /dev/null
@@ -1,16 +0,0 @@
-// Copyright 2016 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// +build !go1.9
-
-package http2
-
-import (
-	"net/http"
-)
-
-func configureServer19(s *http.Server, conf *Server) error {
-	// not supported prior to go1.9
-	return nil
-}
diff --git a/http2/server.go b/http2/server.go
index 174c89b..b57b6e2 100644
--- a/http2/server.go
+++ b/http2/server.go
@@ -28,6 +28,7 @@
 import (
 	"bufio"
 	"bytes"
+	"context"
 	"crypto/tls"
 	"errors"
 	"fmt"
@@ -209,12 +210,14 @@
 		conf = new(Server)
 	}
 	conf.state = &serverInternalState{activeConns: make(map[*serverConn]struct{})}
-	if err := configureServer18(s, conf); err != nil {
-		return err
+	if h1, h2 := s, conf; h2.IdleTimeout == 0 {
+		if h1.IdleTimeout != 0 {
+			h2.IdleTimeout = h1.IdleTimeout
+		} else {
+			h2.IdleTimeout = h1.ReadTimeout
+		}
 	}
-	if err := configureServer19(s, conf); err != nil {
-		return err
-	}
+	s.RegisterOnShutdown(conf.state.startGracefulShutdown)
 
 	if s.TLSConfig == nil {
 		s.TLSConfig = new(tls.Config)
@@ -435,6 +438,15 @@
 	sc.serve()
 }
 
+func serverConnBaseContext(c net.Conn, opts *ServeConnOpts) (ctx context.Context, cancel func()) {
+	ctx, cancel = context.WithCancel(context.Background())
+	ctx = context.WithValue(ctx, http.LocalAddrContextKey, c.LocalAddr())
+	if hs := opts.baseConfig(); hs != nil {
+		ctx = context.WithValue(ctx, http.ServerContextKey, hs)
+	}
+	return
+}
+
 func (sc *serverConn) rejectConn(err ErrCode, debug string) {
 	sc.vlogf("http2: server rejecting conn: %v, %s", err, debug)
 	// ignoring errors. hanging up anyway.
@@ -450,7 +462,7 @@
 	conn             net.Conn
 	bw               *bufferedWriter // writing to conn
 	handler          http.Handler
-	baseCtx          contextContext
+	baseCtx          context.Context
 	framer           *Framer
 	doneServing      chan struct{}          // closed when serverConn.serve ends
 	readFrameCh      chan readFrameResult   // written by serverConn.readFrames
@@ -530,7 +542,7 @@
 	id        uint32
 	body      *pipe       // non-nil if expecting DATA frames
 	cw        closeWaiter // closed wait stream transitions to closed state
-	ctx       contextContext
+	ctx       context.Context
 	cancelCtx func()
 
 	// owned by serverConn's serve loop:
@@ -1882,7 +1894,7 @@
 		panic("internal error: cannot create stream with id 0")
 	}
 
-	ctx, cancelCtx := contextWithCancel(sc.baseCtx)
+	ctx, cancelCtx := context.WithCancel(sc.baseCtx)
 	st := &stream{
 		sc:        sc,
 		id:        id,
@@ -2048,7 +2060,7 @@
 		Body:       body,
 		Trailer:    trailer,
 	}
-	req = requestWithContext(req, st.ctx)
+	req = req.WithContext(st.ctx)
 
 	rws := responseWriterStatePool.Get().(*responseWriterState)
 	bwSave := rws.bw
@@ -2076,7 +2088,7 @@
 				stream: rw.rws.stream,
 			})
 			// Same as net/http:
-			if shouldLogPanic(e) {
+			if e != nil && e != http.ErrAbortHandler {
 				const size = 64 << 10
 				buf := make([]byte, size)
 				buf = buf[:runtime.Stack(buf, false)]
@@ -2638,14 +2650,9 @@
 	ErrPushLimitReached = errors.New("http2: push would exceed peer's SETTINGS_MAX_CONCURRENT_STREAMS")
 )
 
-// pushOptions is the internal version of http.PushOptions, which we
-// cannot include here because it's only defined in Go 1.8 and later.
-type pushOptions struct {
-	Method string
-	Header http.Header
-}
+var _ http.Pusher = (*responseWriter)(nil)
 
-func (w *responseWriter) push(target string, opts pushOptions) error {
+func (w *responseWriter) Push(target string, opts *http.PushOptions) error {
 	st := w.rws.stream
 	sc := st.sc
 	sc.serveG.checkNotOn()
@@ -2656,6 +2663,10 @@
 		return ErrRecursivePush
 	}
 
+	if opts == nil {
+		opts = new(http.PushOptions)
+	}
+
 	// Default options.
 	if opts.Method == "" {
 		opts.Method = "GET"
diff --git a/http2/server_push_test.go b/http2/server_push_test.go
index 918fd30..6e57de0 100644
--- a/http2/server_push_test.go
+++ b/http2/server_push_test.go
@@ -2,8 +2,6 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build go1.8
-
 package http2
 
 import (
diff --git a/http2/server_test.go b/http2/server_test.go
index bb19c96..e5be1a6 100644
--- a/http2/server_test.go
+++ b/http2/server_test.go
@@ -6,6 +6,7 @@
 
 import (
 	"bytes"
+	"context"
 	"crypto/tls"
 	"errors"
 	"flag"
@@ -3850,3 +3851,47 @@
 
 	st.wantRSTStream(1, ErrCodeStreamClosed)
 }
+
+func TestServerGracefulShutdown(t *testing.T) {
+	var st *serverTester
+	handlerDone := make(chan struct{})
+	st = newServerTester(t, func(w http.ResponseWriter, r *http.Request) {
+		defer close(handlerDone)
+		go st.ts.Config.Shutdown(context.Background())
+
+		ga := st.wantGoAway()
+		if ga.ErrCode != ErrCodeNo {
+			t.Errorf("GOAWAY error = %v; want ErrCodeNo", ga.ErrCode)
+		}
+		if ga.LastStreamID != 1 {
+			t.Errorf("GOAWAY LastStreamID = %v; want 1", ga.LastStreamID)
+		}
+
+		w.Header().Set("x-foo", "bar")
+	})
+	defer st.Close()
+
+	st.greet()
+	st.bodylessReq1()
+
+	select {
+	case <-handlerDone:
+	case <-time.After(5 * time.Second):
+		t.Fatalf("server did not shutdown?")
+	}
+	hf := st.wantHeaders()
+	goth := st.decodeHeader(hf.HeaderBlockFragment())
+	wanth := [][2]string{
+		{":status", "200"},
+		{"x-foo", "bar"},
+		{"content-length", "0"},
+	}
+	if !reflect.DeepEqual(goth, wanth) {
+		t.Errorf("Got headers %v; want %v", goth, wanth)
+	}
+
+	n, err := st.cc.Read([]byte{0})
+	if n != 0 || err == nil {
+		t.Errorf("Read = %v, %v; want 0, non-nil", n, err)
+	}
+}
diff --git a/http2/transport.go b/http2/transport.go
index 9d1f2fa..2c9fe88 100644
--- a/http2/transport.go
+++ b/http2/transport.go
@@ -10,6 +10,7 @@
 	"bufio"
 	"bytes"
 	"compress/gzip"
+	"context"
 	"crypto/rand"
 	"crypto/tls"
 	"errors"
@@ -21,6 +22,7 @@
 	mathrand "math/rand"
 	"net"
 	"net/http"
+	"net/http/httptrace"
 	"net/textproto"
 	"sort"
 	"strconv"
@@ -118,16 +120,56 @@
 	return t.DisableCompression || (t.t1 != nil && t.t1.DisableCompression)
 }
 
-var errTransportVersion = errors.New("http2: ConfigureTransport is only supported starting at Go 1.6")
-
 // ConfigureTransport configures a net/http HTTP/1 Transport to use HTTP/2.
-// It requires Go 1.6 or later and returns an error if the net/http package is too old
-// or if t1 has already been HTTP/2-enabled.
+// It returns an error if t1 has already been HTTP/2-enabled.
 func ConfigureTransport(t1 *http.Transport) error {
-	_, err := configureTransport(t1) // in configure_transport.go (go1.6) or not_go16.go
+	_, err := configureTransport(t1)
 	return err
 }
 
+func configureTransport(t1 *http.Transport) (*Transport, error) {
+	connPool := new(clientConnPool)
+	t2 := &Transport{
+		ConnPool: noDialClientConnPool{connPool},
+		t1:       t1,
+	}
+	connPool.t = t2
+	if err := registerHTTPSProtocol(t1, noDialH2RoundTripper{t2}); err != nil {
+		return nil, err
+	}
+	if t1.TLSClientConfig == nil {
+		t1.TLSClientConfig = new(tls.Config)
+	}
+	if !strSliceContains(t1.TLSClientConfig.NextProtos, "h2") {
+		t1.TLSClientConfig.NextProtos = append([]string{"h2"}, t1.TLSClientConfig.NextProtos...)
+	}
+	if !strSliceContains(t1.TLSClientConfig.NextProtos, "http/1.1") {
+		t1.TLSClientConfig.NextProtos = append(t1.TLSClientConfig.NextProtos, "http/1.1")
+	}
+	upgradeFn := func(authority string, c *tls.Conn) http.RoundTripper {
+		addr := authorityAddr("https", authority)
+		if used, err := connPool.addConnIfNeeded(addr, t2, c); err != nil {
+			go c.Close()
+			return erringRoundTripper{err}
+		} else if !used {
+			// Turns out we don't need this c.
+			// For example, two goroutines made requests to the same host
+			// at the same time, both kicking off TCP dials. (since protocol
+			// was unknown)
+			go c.Close()
+		}
+		return t2
+	}
+	if m := t1.TLSNextProto; len(m) == 0 {
+		t1.TLSNextProto = map[string]func(string, *tls.Conn) http.RoundTripper{
+			"h2": upgradeFn,
+		}
+	} else {
+		m["h2"] = upgradeFn
+	}
+	return t2, nil
+}
+
 func (t *Transport) connPool() ClientConnPool {
 	t.connPoolOnce.Do(t.initConnPool)
 	return t.connPoolOrDef
@@ -192,7 +234,7 @@
 type clientStream struct {
 	cc            *ClientConn
 	req           *http.Request
-	trace         *clientTrace // or nil
+	trace         *httptrace.ClientTrace // or nil
 	ID            uint32
 	resc          chan resAndError
 	bufPipe       pipe // buffered pipe with the flow-controlled response payload
@@ -226,7 +268,7 @@
 // channel to be signaled. A non-nil error is returned only if the request was
 // canceled.
 func awaitRequestCancel(req *http.Request, done <-chan struct{}) error {
-	ctx := reqContext(req)
+	ctx := req.Context()
 	if req.Cancel == nil && ctx.Done() == nil {
 		return nil
 	}
@@ -401,8 +443,8 @@
 				select {
 				case <-time.After(time.Second * time.Duration(backoff)):
 					continue
-				case <-reqContext(req).Done():
-					return nil, reqContext(req).Err()
+				case <-req.Context().Done():
+					return nil, req.Context().Err()
 				}
 			}
 		}
@@ -439,16 +481,15 @@
 	}
 	// If the Body is nil (or http.NoBody), it's safe to reuse
 	// this request and its Body.
-	if req.Body == nil || reqBodyIsNoBody(req.Body) {
+	if req.Body == nil || req.Body == http.NoBody {
 		return req, nil
 	}
 
 	// If the request body can be reset back to its original
 	// state via the optional req.GetBody, do that.
-	getBody := reqGetBody(req) // Go 1.8: getBody = req.GetBody
-	if getBody != nil {
+	if req.GetBody != nil {
 		// TODO: consider a req.Body.Close here? or audit that all caller paths do?
-		body, err := getBody()
+		body, err := req.GetBody()
 		if err != nil {
 			return nil, err
 		}
@@ -494,7 +535,7 @@
 func (t *Transport) newTLSConfig(host string) *tls.Config {
 	cfg := new(tls.Config)
 	if t.TLSClientConfig != nil {
-		*cfg = *cloneTLSConfig(t.TLSClientConfig)
+		*cfg = *t.TLSClientConfig.Clone()
 	}
 	if !strSliceContains(cfg.NextProtos, NextProtoTLS) {
 		cfg.NextProtos = append([]string{NextProtoTLS}, cfg.NextProtos...)
@@ -545,7 +586,7 @@
 	if t.t1 == nil {
 		return 0
 	}
-	return transportExpectContinueTimeout(t.t1)
+	return t.t1.ExpectContinueTimeout
 }
 
 func (t *Transport) NewClientConn(c net.Conn) (*ClientConn, error) {
@@ -711,8 +752,7 @@
 var shutdownEnterWaitStateHook = func() {}
 
 // Shutdown gracefully close the client connection, waiting for running streams to complete.
-// Public implementation is in go17.go and not_go17.go
-func (cc *ClientConn) shutdown(ctx contextContext) error {
+func (cc *ClientConn) Shutdown(ctx context.Context) error {
 	if err := cc.sendGoAway(); err != nil {
 		return err
 	}
@@ -882,7 +922,7 @@
 // req.ContentLength, where 0 actually means zero (not unknown) and -1
 // means unknown.
 func actualContentLength(req *http.Request) int64 {
-	if req.Body == nil || reqBodyIsNoBody(req.Body) {
+	if req.Body == nil || req.Body == http.NoBody {
 		return 0
 	}
 	if req.ContentLength != 0 {
@@ -952,7 +992,7 @@
 
 	cs := cc.newStream()
 	cs.req = req
-	cs.trace = requestTrace(req)
+	cs.trace = httptrace.ContextClientTrace(req.Context())
 	cs.requestedGzip = requestedGzip
 	bodyWriter := cc.t.getBodyWriterState(cs, body)
 	cs.on100 = bodyWriter.on100
@@ -990,7 +1030,7 @@
 
 	readLoopResCh := cs.resc
 	bodyWritten := false
-	ctx := reqContext(req)
+	ctx := req.Context()
 
 	handleReadLoopResponse := func(re resAndError) (*http.Response, bool, error) {
 		res := re.res
@@ -1416,7 +1456,7 @@
 		return nil, errRequestHeaderListSize
 	}
 
-	trace := requestTrace(req)
+	trace := httptrace.ContextClientTrace(req.Context())
 	traceHeaders := traceHasWroteHeaderField(trace)
 
 	// Header list size is ok. Write the headers.
@@ -1839,7 +1879,7 @@
 		res.Header.Del("Content-Length")
 		res.ContentLength = -1
 		res.Body = &gzipReader{body: res.Body}
-		setResponseUncompressed(res)
+		res.Uncompressed = true
 	}
 	return res, nil
 }
@@ -2216,8 +2256,7 @@
 }
 
 // Ping sends a PING frame to the server and waits for the ack.
-// Public implementation is in go17.go and not_go17.go
-func (cc *ClientConn) ping(ctx contextContext) error {
+func (cc *ClientConn) Ping(ctx context.Context) error {
 	c := make(chan struct{})
 	// Generate a random payload
 	var p [8]byte
@@ -2451,3 +2490,91 @@
 func isConnectionCloseRequest(req *http.Request) bool {
 	return req.Close || httpguts.HeaderValuesContainsToken(req.Header["Connection"], "close")
 }
+
+// registerHTTPSProtocol calls Transport.RegisterProtocol but
+// converting panics into errors.
+func registerHTTPSProtocol(t *http.Transport, rt noDialH2RoundTripper) (err error) {
+	defer func() {
+		if e := recover(); e != nil {
+			err = fmt.Errorf("%v", e)
+		}
+	}()
+	t.RegisterProtocol("https", rt)
+	return nil
+}
+
+// noDialH2RoundTripper is a RoundTripper which only tries to complete the request
+// if there's already has a cached connection to the host.
+// (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.Transport.RoundTrip(req)
+	if isNoCachedConnError(err) {
+		return nil, http.ErrSkipAltProtocol
+	}
+	return res, err
+}
+
+func (t *Transport) idleConnTimeout() time.Duration {
+	if t.t1 != nil {
+		return t.t1.IdleConnTimeout
+	}
+	return 0
+}
+
+func traceGetConn(req *http.Request, hostPort string) {
+	trace := httptrace.ContextClientTrace(req.Context())
+	if trace == nil || trace.GetConn == nil {
+		return
+	}
+	trace.GetConn(hostPort)
+}
+
+func traceGotConn(req *http.Request, cc *ClientConn) {
+	trace := httptrace.ContextClientTrace(req.Context())
+	if trace == nil || trace.GotConn == nil {
+		return
+	}
+	ci := httptrace.GotConnInfo{Conn: cc.tconn}
+	cc.mu.Lock()
+	ci.Reused = cc.nextStreamID > 1
+	ci.WasIdle = len(cc.streams) == 0 && ci.Reused
+	if ci.WasIdle && !cc.lastActive.IsZero() {
+		ci.IdleTime = time.Now().Sub(cc.lastActive)
+	}
+	cc.mu.Unlock()
+
+	trace.GotConn(ci)
+}
+
+func traceWroteHeaders(trace *httptrace.ClientTrace) {
+	if trace != nil && trace.WroteHeaders != nil {
+		trace.WroteHeaders()
+	}
+}
+
+func traceGot100Continue(trace *httptrace.ClientTrace) {
+	if trace != nil && trace.Got100Continue != nil {
+		trace.Got100Continue()
+	}
+}
+
+func traceWait100Continue(trace *httptrace.ClientTrace) {
+	if trace != nil && trace.Wait100Continue != nil {
+		trace.Wait100Continue()
+	}
+}
+
+func traceWroteRequest(trace *httptrace.ClientTrace, err error) {
+	if trace != nil && trace.WroteRequest != nil {
+		trace.WroteRequest(httptrace.WroteRequestInfo{Err: err})
+	}
+}
+
+func traceFirstResponseByte(trace *httptrace.ClientTrace) {
+	if trace != nil && trace.GotFirstResponseByte != nil {
+		trace.GotFirstResponseByte()
+	}
+}
diff --git a/http2/transport_test.go b/http2/transport_test.go
index 5b5c076..f61ff50 100644
--- a/http2/transport_test.go
+++ b/http2/transport_test.go
@@ -7,6 +7,7 @@
 import (
 	"bufio"
 	"bytes"
+	"context"
 	"crypto/tls"
 	"errors"
 	"flag"
@@ -31,7 +32,6 @@
 	"testing"
 	"time"
 
-	"golang.org/x/net/context"
 	"golang.org/x/net/http2/hpack"
 )
 
@@ -424,7 +424,7 @@
 		},
 		// http.NoBody means 0, not -1.
 		3: {
-			req:  &http.Request{Body: go18httpNoBody()},
+			req:  &http.Request{Body: http.NoBody},
 			want: 0,
 		},
 	}
@@ -564,9 +564,6 @@
 func TestConfigureTransport(t *testing.T) {
 	t1 := &http.Transport{}
 	err := ConfigureTransport(t1)
-	if err == errTransportVersion {
-		t.Skip(err)
-	}
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -3784,7 +3781,7 @@
 	unblockClient := make(chan bool)
 
 	ct.client = func() error {
-		req, _ := http.NewRequest("GET", "https://dummy.tld/", go18httpNoBody())
+		req, _ := http.NewRequest("GET", "https://dummy.tld/", http.NoBody)
 		ct.tr.RoundTrip(req)
 		<-unblockClient
 		return nil
@@ -4024,8 +4021,8 @@
 	}
 	switch closeMode {
 	case shutdownCancel:
-		if err = cc.Shutdown(canceledCtx); err != errCanceled {
-			t.Errorf("got %v, want %v", err, errCanceled)
+		if err = cc.Shutdown(canceledCtx); err != context.Canceled {
+			t.Errorf("got %v, want %v", err, context.Canceled)
 		}
 		if cc.closing == false {
 			t.Error("expected closing to be true")