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