// Parses information from a http2 request with prior knowledge (RFC 7540 Section 3.4)
Parses information from a http2 request with prior knowledge (RFC 7540 Section 3.4)
// Parses information from a http2 request with prior knowledge ( RFC 7540 Section 3 . 4 )
func (m MatchHTTP) handleHttp2WithPriorKnowledge(reader io.Reader, req *http.Request) error {
	if req.Method != "PRI" || len(req.Header) != 0 || req.URL.Path != "*" || req.Proto != "HTTP/2.0" {
		return nil
	}
	const expectedBody = "SM\r\n\r\n"
	body := make([]byte, len(expectedBody))
	n, err := io.ReadFull(reader, body)
	if err != nil {
		return err
	}
	if string(body[:n]) != expectedBody {
		return nil
	}
	framer := http2.NewFramer(io.Discard, reader)
	var frame http2.Frame
	for i := 0; i < 3; i++ {
		frame, err = framer.ReadFrame()
		if err != nil {
			return err
		}
		if frame.Header().Type == http2.FrameHeaders {
			break
		}
	}
	if frame.Header().Type != http2.FrameHeaders {
		return fmt.Errorf("failed to read a http2 headers frame after 3 attemps")
	}
	decoder := hpack.NewDecoder(4096, nil) 
	headers, err := decoder.DecodeFull((frame.(*http2.HeadersFrame)).HeaderBlockFragment())
	if err != nil {
		return err
	}
	var scheme string
	var authority string
	var path string
	for _, h := range headers {
		if h.Name == ":method" {
			req.Method = h.Value
		} else if h.Name == ":path" {
			path = h.Value
			req.RequestURI = h.Value
		} else if h.Name == ":scheme" {
			scheme = h.Value
		} else if h.Name == ":authority" {
			authority = h.Value
			req.Host = h.Value
		} else {
			req.Header.Add(h.Name, h.Value)
		}
	}
	req.URL, err = url.Parse(fmt.Sprintf("%s://%s%s", scheme, authority, path))
	return err
}
func ( m MatchHTTP ) handleHttp2WithPriorKnowledge ( reader io . Reader , req * http . Request ) error { if req . Method != " " || len ( req . Header ) != 0 || req . URL . Path != " " || req . Proto != " " { return nil } const expectedBody = " \r \n \r \n " body := make ( [ ] byte , len ( expectedBody ) ) n , err := io . ReadFull ( reader , body ) if err != nil { return err } if string ( body [ : n ] ) != expectedBody { return nil } framer := http2 . NewFramer ( io . Discard , reader ) var frame http2 . Frame for i := 0 ; i < 3 ; i ++ { frame , err = framer . ReadFrame ( ) if err != nil { return err } if frame . Header ( ) . Type == http2 . FrameHeaders { break } } if frame . Header ( ) . Type != http2 . FrameHeaders { return fmt . Errorf ( " " ) } decoder := hpack . NewDecoder ( 4096 , nil ) headers , err := decoder . DecodeFull ( ( frame . ( * http2 . HeadersFrame ) ) . HeaderBlockFragment ( ) ) if err != nil { return err } var scheme string var authority string var path string for _ , h := range headers { if h . Name == " " { req . Method = h . Value } else if h . Name == " " { path = h . Value req . RequestURI = h . Value } else if h . Name == " " { scheme = h . Value } else if h . Name == " " { authority = h . Value req . Host = h . Value } else { req . Header . Add ( h . Name , h . Value ) } } req . URL , err = url . Parse ( fmt . Sprintf ( " " , scheme , authority , path ) ) return err }
Parses information from a http2 request with prior knowledge (RFC 7540 Section 3.4)
Parses information from a http2 request with prior knowledge ( RFC 7540 Section 3 . 4 )
// Does req contain a valid http2 magic? // https://github.com/golang/net/blob/a630d4f3e7a22f21271532b4b88e1693824a838f/http2/h2c/h2c.go#L74 // read the first 3 frames until we get a headers frame (skipping settings & window update frames) // max table size 4096 from http2.initialHeaderTableSize // According to http.Request.URL docs it only contains the value of RequestURI (so path only), // but we can fill in more information