github.com/Andyfoo/golang/x/net@v0.0.0-20190901054642-57c1bf301704/http2/h2c/h2c.go (about)

     1  // Copyright 2018 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  // Package h2c implements the unencrypted "h2c" form of HTTP/2.
     6  //
     7  // The h2c protocol is the non-TLS version of HTTP/2 which is not available from
     8  // net/http or github.com/Andyfoo/golang/x/net/http2.
     9  package h2c
    10  
    11  import (
    12  	"bufio"
    13  	"bytes"
    14  	"encoding/base64"
    15  	"encoding/binary"
    16  	"errors"
    17  	"fmt"
    18  	"io"
    19  	"log"
    20  	"net"
    21  	"net/http"
    22  	"net/textproto"
    23  	"os"
    24  	"strings"
    25  
    26  	"github.com/Andyfoo/golang/x/net/http/httpguts"
    27  	"github.com/Andyfoo/golang/x/net/http2"
    28  	"github.com/Andyfoo/golang/x/net/http2/hpack"
    29  )
    30  
    31  var (
    32  	http2VerboseLogs bool
    33  )
    34  
    35  func init() {
    36  	e := os.Getenv("GODEBUG")
    37  	if strings.Contains(e, "http2debug=1") || strings.Contains(e, "http2debug=2") {
    38  		http2VerboseLogs = true
    39  	}
    40  }
    41  
    42  // h2cHandler is a Handler which implements h2c by hijacking the HTTP/1 traffic
    43  // that should be h2c traffic. There are two ways to begin a h2c connection
    44  // (RFC 7540 Section 3.2 and 3.4): (1) Starting with Prior Knowledge - this
    45  // works by starting an h2c connection with a string of bytes that is valid
    46  // HTTP/1, but unlikely to occur in practice and (2) Upgrading from HTTP/1 to
    47  // h2c - this works by using the HTTP/1 Upgrade header to request an upgrade to
    48  // h2c. When either of those situations occur we hijack the HTTP/1 connection,
    49  // convert it to a HTTP/2 connection and pass the net.Conn to http2.ServeConn.
    50  type h2cHandler struct {
    51  	Handler http.Handler
    52  	s       *http2.Server
    53  }
    54  
    55  // NewHandler returns an http.Handler that wraps h, intercepting any h2c
    56  // traffic. If a request is an h2c connection, it's hijacked and redirected to
    57  // s.ServeConn. Otherwise the returned Handler just forwards requests to h. This
    58  // works because h2c is designed to be parseable as valid HTTP/1, but ignored by
    59  // any HTTP server that does not handle h2c. Therefore we leverage the HTTP/1
    60  // compatible parts of the Go http library to parse and recognize h2c requests.
    61  // Once a request is recognized as h2c, we hijack the connection and convert it
    62  // to an HTTP/2 connection which is understandable to s.ServeConn. (s.ServeConn
    63  // understands HTTP/2 except for the h2c part of it.)
    64  func NewHandler(h http.Handler, s *http2.Server) http.Handler {
    65  	return &h2cHandler{
    66  		Handler: h,
    67  		s:       s,
    68  	}
    69  }
    70  
    71  // ServeHTTP implement the h2c support that is enabled by h2c.GetH2CHandler.
    72  func (s h2cHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    73  	// Handle h2c with prior knowledge (RFC 7540 Section 3.4)
    74  	if r.Method == "PRI" && len(r.Header) == 0 && r.URL.Path == "*" && r.Proto == "HTTP/2.0" {
    75  		if http2VerboseLogs {
    76  			log.Print("h2c: attempting h2c with prior knowledge.")
    77  		}
    78  		conn, err := initH2CWithPriorKnowledge(w)
    79  		if err != nil {
    80  			if http2VerboseLogs {
    81  				log.Printf("h2c: error h2c with prior knowledge: %v", err)
    82  			}
    83  			return
    84  		}
    85  		defer conn.Close()
    86  
    87  		s.s.ServeConn(conn, &http2.ServeConnOpts{Handler: s.Handler})
    88  		return
    89  	}
    90  	// Handle Upgrade to h2c (RFC 7540 Section 3.2)
    91  	if conn, err := h2cUpgrade(w, r); err == nil {
    92  		defer conn.Close()
    93  
    94  		s.s.ServeConn(conn, &http2.ServeConnOpts{Handler: s.Handler})
    95  		return
    96  	}
    97  
    98  	s.Handler.ServeHTTP(w, r)
    99  	return
   100  }
   101  
   102  // initH2CWithPriorKnowledge implements creating a h2c connection with prior
   103  // knowledge (Section 3.4) and creates a net.Conn suitable for http2.ServeConn.
   104  // All we have to do is look for the client preface that is suppose to be part
   105  // of the body, and reforward the client preface on the net.Conn this function
   106  // creates.
   107  func initH2CWithPriorKnowledge(w http.ResponseWriter) (net.Conn, error) {
   108  	hijacker, ok := w.(http.Hijacker)
   109  	if !ok {
   110  		panic("Hijack not supported.")
   111  	}
   112  	conn, rw, err := hijacker.Hijack()
   113  	if err != nil {
   114  		panic(fmt.Sprintf("Hijack failed: %v", err))
   115  	}
   116  
   117  	const expectedBody = "SM\r\n\r\n"
   118  
   119  	buf := make([]byte, len(expectedBody))
   120  	n, err := io.ReadFull(rw, buf)
   121  	if err != nil {
   122  		return nil, fmt.Errorf("could not read from the buffer: %s", err)
   123  	}
   124  
   125  	if string(buf[:n]) == expectedBody {
   126  		c := &rwConn{
   127  			Conn:      conn,
   128  			Reader:    io.MultiReader(strings.NewReader(http2.ClientPreface), rw),
   129  			BufWriter: rw.Writer,
   130  		}
   131  		return c, nil
   132  	}
   133  
   134  	conn.Close()
   135  	if http2VerboseLogs {
   136  		log.Printf(
   137  			"h2c: missing the request body portion of the client preface. Wanted: %v Got: %v",
   138  			[]byte(expectedBody),
   139  			buf[0:n],
   140  		)
   141  	}
   142  	return nil, errors.New("invalid client preface")
   143  }
   144  
   145  // drainClientPreface reads a single instance of the HTTP/2 client preface from
   146  // the supplied reader.
   147  func drainClientPreface(r io.Reader) error {
   148  	var buf bytes.Buffer
   149  	prefaceLen := int64(len(http2.ClientPreface))
   150  	n, err := io.CopyN(&buf, r, prefaceLen)
   151  	if err != nil {
   152  		return err
   153  	}
   154  	if n != prefaceLen || buf.String() != http2.ClientPreface {
   155  		return fmt.Errorf("Client never sent: %s", http2.ClientPreface)
   156  	}
   157  	return nil
   158  }
   159  
   160  // h2cUpgrade establishes a h2c connection using the HTTP/1 upgrade (Section 3.2).
   161  func h2cUpgrade(w http.ResponseWriter, r *http.Request) (net.Conn, error) {
   162  	if !isH2CUpgrade(r.Header) {
   163  		return nil, errors.New("non-conforming h2c headers")
   164  	}
   165  
   166  	// Initial bytes we put into conn to fool http2 server
   167  	initBytes, _, err := convertH1ReqToH2(r)
   168  	if err != nil {
   169  		return nil, err
   170  	}
   171  
   172  	hijacker, ok := w.(http.Hijacker)
   173  	if !ok {
   174  		return nil, errors.New("hijack not supported.")
   175  	}
   176  	conn, rw, err := hijacker.Hijack()
   177  	if err != nil {
   178  		return nil, fmt.Errorf("hijack failed: %v", err)
   179  	}
   180  
   181  	rw.Write([]byte("HTTP/1.1 101 Switching Protocols\r\n" +
   182  		"Connection: Upgrade\r\n" +
   183  		"Upgrade: h2c\r\n\r\n"))
   184  	rw.Flush()
   185  
   186  	// A conforming client will now send an H2 client preface which need to drain
   187  	// since we already sent this.
   188  	if err := drainClientPreface(rw); err != nil {
   189  		return nil, err
   190  	}
   191  
   192  	c := &rwConn{
   193  		Conn:      conn,
   194  		Reader:    io.MultiReader(initBytes, rw),
   195  		BufWriter: newSettingsAckSwallowWriter(rw.Writer),
   196  	}
   197  	return c, nil
   198  }
   199  
   200  // convert the data contained in the HTTP/1 upgrade request into the HTTP/2
   201  // version in byte form.
   202  func convertH1ReqToH2(r *http.Request) (*bytes.Buffer, []http2.Setting, error) {
   203  	h2Bytes := bytes.NewBuffer([]byte((http2.ClientPreface)))
   204  	framer := http2.NewFramer(h2Bytes, nil)
   205  	settings, err := getH2Settings(r.Header)
   206  	if err != nil {
   207  		return nil, nil, err
   208  	}
   209  
   210  	if err := framer.WriteSettings(settings...); err != nil {
   211  		return nil, nil, err
   212  	}
   213  
   214  	headerBytes, err := getH2HeaderBytes(r, getMaxHeaderTableSize(settings))
   215  	if err != nil {
   216  		return nil, nil, err
   217  	}
   218  
   219  	maxFrameSize := int(getMaxFrameSize(settings))
   220  	needOneHeader := len(headerBytes) < maxFrameSize
   221  	err = framer.WriteHeaders(http2.HeadersFrameParam{
   222  		StreamID:      1,
   223  		BlockFragment: headerBytes,
   224  		EndHeaders:    needOneHeader,
   225  	})
   226  	if err != nil {
   227  		return nil, nil, err
   228  	}
   229  
   230  	for i := maxFrameSize; i < len(headerBytes); i += maxFrameSize {
   231  		if len(headerBytes)-i > maxFrameSize {
   232  			if err := framer.WriteContinuation(1,
   233  				false, // endHeaders
   234  				headerBytes[i:maxFrameSize]); err != nil {
   235  				return nil, nil, err
   236  			}
   237  		} else {
   238  			if err := framer.WriteContinuation(1,
   239  				true, // endHeaders
   240  				headerBytes[i:]); err != nil {
   241  				return nil, nil, err
   242  			}
   243  		}
   244  	}
   245  
   246  	return h2Bytes, settings, nil
   247  }
   248  
   249  // getMaxFrameSize returns the SETTINGS_MAX_FRAME_SIZE. If not present default
   250  // value is 16384 as specified by RFC 7540 Section 6.5.2.
   251  func getMaxFrameSize(settings []http2.Setting) uint32 {
   252  	for _, setting := range settings {
   253  		if setting.ID == http2.SettingMaxFrameSize {
   254  			return setting.Val
   255  		}
   256  	}
   257  	return 16384
   258  }
   259  
   260  // getMaxHeaderTableSize returns the SETTINGS_HEADER_TABLE_SIZE. If not present
   261  // default value is 4096 as specified by RFC 7540 Section 6.5.2.
   262  func getMaxHeaderTableSize(settings []http2.Setting) uint32 {
   263  	for _, setting := range settings {
   264  		if setting.ID == http2.SettingHeaderTableSize {
   265  			return setting.Val
   266  		}
   267  	}
   268  	return 4096
   269  }
   270  
   271  // bufWriter is a Writer interface that also has a Flush method.
   272  type bufWriter interface {
   273  	io.Writer
   274  	Flush() error
   275  }
   276  
   277  // rwConn implements net.Conn but overrides Read and Write so that reads and
   278  // writes are forwarded to the provided io.Reader and bufWriter.
   279  type rwConn struct {
   280  	net.Conn
   281  	io.Reader
   282  	BufWriter bufWriter
   283  }
   284  
   285  // Read forwards reads to the underlying Reader.
   286  func (c *rwConn) Read(p []byte) (int, error) {
   287  	return c.Reader.Read(p)
   288  }
   289  
   290  // Write forwards writes to the underlying bufWriter and immediately flushes.
   291  func (c *rwConn) Write(p []byte) (int, error) {
   292  	n, err := c.BufWriter.Write(p)
   293  	if err := c.BufWriter.Flush(); err != nil {
   294  		return 0, err
   295  	}
   296  	return n, err
   297  }
   298  
   299  // settingsAckSwallowWriter is a writer that normally forwards bytes to its
   300  // underlying Writer, but swallows the first SettingsAck frame that it sees.
   301  type settingsAckSwallowWriter struct {
   302  	Writer     *bufio.Writer
   303  	buf        []byte
   304  	didSwallow bool
   305  }
   306  
   307  // newSettingsAckSwallowWriter returns a new settingsAckSwallowWriter.
   308  func newSettingsAckSwallowWriter(w *bufio.Writer) *settingsAckSwallowWriter {
   309  	return &settingsAckSwallowWriter{
   310  		Writer:     w,
   311  		buf:        make([]byte, 0),
   312  		didSwallow: false,
   313  	}
   314  }
   315  
   316  // Write implements io.Writer interface. Normally forwards bytes to w.Writer,
   317  // except for the first Settings ACK frame that it sees.
   318  func (w *settingsAckSwallowWriter) Write(p []byte) (int, error) {
   319  	if !w.didSwallow {
   320  		w.buf = append(w.buf, p...)
   321  		// Process all the frames we have collected into w.buf
   322  		for {
   323  			// Append until we get full frame header which is 9 bytes
   324  			if len(w.buf) < 9 {
   325  				break
   326  			}
   327  			// Check if we have collected a whole frame.
   328  			fh, err := http2.ReadFrameHeader(bytes.NewBuffer(w.buf))
   329  			if err != nil {
   330  				// Corrupted frame, fail current Write
   331  				return 0, err
   332  			}
   333  			fSize := fh.Length + 9
   334  			if uint32(len(w.buf)) < fSize {
   335  				// Have not collected whole frame. Stop processing buf, and withold on
   336  				// forward bytes to w.Writer until we get the full frame.
   337  				break
   338  			}
   339  
   340  			// We have now collected a whole frame.
   341  			if fh.Type == http2.FrameSettings && fh.Flags.Has(http2.FlagSettingsAck) {
   342  				// If Settings ACK frame, do not forward to underlying writer, remove
   343  				// bytes from w.buf, and record that we have swallowed Settings Ack
   344  				// frame.
   345  				w.didSwallow = true
   346  				w.buf = w.buf[fSize:]
   347  				continue
   348  			}
   349  
   350  			// Not settings ack frame. Forward bytes to w.Writer.
   351  			if _, err := w.Writer.Write(w.buf[:fSize]); err != nil {
   352  				// Couldn't forward bytes. Fail current Write.
   353  				return 0, err
   354  			}
   355  			w.buf = w.buf[fSize:]
   356  		}
   357  		return len(p), nil
   358  	}
   359  	return w.Writer.Write(p)
   360  }
   361  
   362  // Flush calls w.Writer.Flush.
   363  func (w *settingsAckSwallowWriter) Flush() error {
   364  	return w.Writer.Flush()
   365  }
   366  
   367  // isH2CUpgrade returns true if the header properly request an upgrade to h2c
   368  // as specified by Section 3.2.
   369  func isH2CUpgrade(h http.Header) bool {
   370  	return httpguts.HeaderValuesContainsToken(h[textproto.CanonicalMIMEHeaderKey("Upgrade")], "h2c") &&
   371  		httpguts.HeaderValuesContainsToken(h[textproto.CanonicalMIMEHeaderKey("Connection")], "HTTP2-Settings")
   372  }
   373  
   374  // getH2Settings returns the []http2.Setting that are encoded in the
   375  // HTTP2-Settings header.
   376  func getH2Settings(h http.Header) ([]http2.Setting, error) {
   377  	vals, ok := h[textproto.CanonicalMIMEHeaderKey("HTTP2-Settings")]
   378  	if !ok {
   379  		return nil, errors.New("missing HTTP2-Settings header")
   380  	}
   381  	if len(vals) != 1 {
   382  		return nil, fmt.Errorf("expected 1 HTTP2-Settings. Got: %v", vals)
   383  	}
   384  	settings, err := decodeSettings(vals[0])
   385  	if err != nil {
   386  		return nil, fmt.Errorf("Invalid HTTP2-Settings: %q", vals[0])
   387  	}
   388  	return settings, nil
   389  }
   390  
   391  // decodeSettings decodes the base64url header value of the HTTP2-Settings
   392  // header. RFC 7540 Section 3.2.1.
   393  func decodeSettings(headerVal string) ([]http2.Setting, error) {
   394  	b, err := base64.RawURLEncoding.DecodeString(headerVal)
   395  	if err != nil {
   396  		return nil, err
   397  	}
   398  	if len(b)%6 != 0 {
   399  		return nil, err
   400  	}
   401  	settings := make([]http2.Setting, 0)
   402  	for i := 0; i < len(b)/6; i++ {
   403  		settings = append(settings, http2.Setting{
   404  			ID:  http2.SettingID(binary.BigEndian.Uint16(b[i*6 : i*6+2])),
   405  			Val: binary.BigEndian.Uint32(b[i*6+2 : i*6+6]),
   406  		})
   407  	}
   408  
   409  	return settings, nil
   410  }
   411  
   412  // getH2HeaderBytes return the headers in r a []bytes encoded by HPACK.
   413  func getH2HeaderBytes(r *http.Request, maxHeaderTableSize uint32) ([]byte, error) {
   414  	headerBytes := bytes.NewBuffer(nil)
   415  	hpackEnc := hpack.NewEncoder(headerBytes)
   416  	hpackEnc.SetMaxDynamicTableSize(maxHeaderTableSize)
   417  
   418  	// Section 8.1.2.3
   419  	err := hpackEnc.WriteField(hpack.HeaderField{
   420  		Name:  ":method",
   421  		Value: r.Method,
   422  	})
   423  	if err != nil {
   424  		return nil, err
   425  	}
   426  
   427  	err = hpackEnc.WriteField(hpack.HeaderField{
   428  		Name:  ":scheme",
   429  		Value: "http",
   430  	})
   431  	if err != nil {
   432  		return nil, err
   433  	}
   434  
   435  	err = hpackEnc.WriteField(hpack.HeaderField{
   436  		Name:  ":authority",
   437  		Value: r.Host,
   438  	})
   439  	if err != nil {
   440  		return nil, err
   441  	}
   442  
   443  	path := r.URL.Path
   444  	if r.URL.RawQuery != "" {
   445  		path = strings.Join([]string{path, r.URL.RawQuery}, "?")
   446  	}
   447  	err = hpackEnc.WriteField(hpack.HeaderField{
   448  		Name:  ":path",
   449  		Value: path,
   450  	})
   451  	if err != nil {
   452  		return nil, err
   453  	}
   454  
   455  	// TODO Implement Section 8.3
   456  
   457  	for header, values := range r.Header {
   458  		// Skip non h2 headers
   459  		if isNonH2Header(header) {
   460  			continue
   461  		}
   462  		for _, v := range values {
   463  			err := hpackEnc.WriteField(hpack.HeaderField{
   464  				Name:  strings.ToLower(header),
   465  				Value: v,
   466  			})
   467  			if err != nil {
   468  				return nil, err
   469  			}
   470  		}
   471  	}
   472  	return headerBytes.Bytes(), nil
   473  }
   474  
   475  // Connection specific headers listed in RFC 7540 Section 8.1.2.2 that are not
   476  // suppose to be transferred to HTTP/2. The Http2-Settings header is skipped
   477  // since already use to create the HTTP/2 SETTINGS frame.
   478  var nonH2Headers = []string{
   479  	"Connection",
   480  	"Keep-Alive",
   481  	"Proxy-Connection",
   482  	"Transfer-Encoding",
   483  	"Upgrade",
   484  	"Http2-Settings",
   485  }
   486  
   487  // isNonH2Header returns true if header should not be transferred to HTTP/2.
   488  func isNonH2Header(header string) bool {
   489  	for _, nonH2h := range nonH2Headers {
   490  		if header == nonH2h {
   491  			return true
   492  		}
   493  	}
   494  	return false
   495  }