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 }