github.com/cloudwego/kitex@v0.9.0/pkg/remote/trans/nphttp2/grpc/grpcframe/frame_parser.go (about) 1 /* 2 * Copyright 2021 The Go Authors. All rights reserved. 3 * 4 * Use of this source code is governed by a BSD-style 5 * license that can be found in the LICENSE file. 6 * 7 * This file may have been modified by CloudWeGo authors. All CloudWeGo 8 * Modifications are Copyright 2022 CloudWeGo Authors. 9 * 10 * Code forked and modified from golang v1.17.4 11 */ 12 13 package grpcframe 14 15 import ( 16 "encoding/binary" 17 "fmt" 18 19 "github.com/cloudwego/netpoll" 20 "golang.org/x/net/http2" 21 "golang.org/x/net/http2/hpack" 22 ) 23 24 /* struct: 25 * DataFrame 26 * HeadersFrame 27 * SettingsFrame 28 * PushPromiseFrame 29 * GoAwayFrame 30 * ContinuationFrame 31 * MetaHeadersFrame 32 */ 33 34 // a frameParser parses a frame given its FrameHeader and payload 35 // bytes. The length of payload will always equal fh.Length (which 36 // might be 0). 37 type frameParser func(fc *frameCache, fh http2.FrameHeader, payload []byte) (http2.Frame, error) 38 39 var frameParsers = []frameParser{ 40 // FrameData: parseDataFrame, 41 http2.FrameHeaders: parseHeadersFrame, 42 http2.FramePriority: parsePriorityFrame, 43 http2.FrameRSTStream: parseRSTStreamFrame, 44 http2.FrameSettings: parseSettingsFrame, 45 http2.FramePushPromise: parsePushPromise, 46 http2.FramePing: parsePingFrame, 47 http2.FrameGoAway: parseGoAwayFrame, 48 http2.FrameWindowUpdate: parseWindowUpdateFrame, 49 http2.FrameContinuation: parseContinuationFrame, 50 } 51 52 func typeFrameParser(t http2.FrameType) frameParser { 53 if 1 <= t && t <= 9 { 54 return frameParsers[t] 55 } 56 return parseUnknownFrame 57 } 58 59 // A DataFrame conveys arbitrary, variable-length sequences of octets 60 // associated with a stream. 61 // See http://http2.github.io/http2-spec/#rfc.section.6.1 62 type DataFrame struct { 63 http2.FrameHeader 64 data []byte // TODO: data = netpoll.Reader here 65 } 66 67 func (f *DataFrame) StreamEnded() bool { 68 return f.FrameHeader.Flags.Has(http2.FlagDataEndStream) 69 } 70 71 // Data returns the frame's data octets, not including any padding 72 // size byte or padding suffix bytes. 73 // The caller must not retain the returned memory past the next 74 // call to ReadFrame. 75 func (f *DataFrame) Data() []byte { 76 return f.data 77 } 78 79 func parseDataFrame(fc *frameCache, fh http2.FrameHeader, payload netpoll.Reader) (http2.Frame, error) { 80 if fh.StreamID == 0 { 81 // DATA frames MUST be associated with a stream. If a 82 // DATA frame is received whose stream identifier 83 // field is 0x0, the recipient MUST respond with a 84 // connection error (Section 5.4.1) of type 85 // PROTOCOL_ERROR. 86 return nil, connError{http2.ErrCodeProtocol, "DATA frame with stream ID 0"} 87 } 88 f := fc.getDataFrame() 89 f.FrameHeader = fh 90 91 var padSize byte 92 payloadLen := int(fh.Length) 93 if fh.Flags.Has(http2.FlagDataPadded) { 94 var err error 95 padSize, err = payload.ReadByte() 96 payloadLen-- 97 if err != nil { 98 return nil, err 99 } 100 } 101 if int(padSize) > payloadLen { 102 // If the length of the padding is greater than the 103 // length of the frame payload, the recipient MUST 104 // treat this as a connection error. 105 // Filed: https://github.com/http2/http2-spec/issues/610 106 return nil, connError{http2.ErrCodeProtocol, "pad size larger than data payload"} 107 } 108 data, err := payload.Next(payloadLen) 109 if err != nil { 110 return nil, err 111 } 112 f.data = data[:payloadLen-int(padSize)] 113 return f, nil 114 } 115 116 // A HeadersFrame is used to open a stream and additionally carries a 117 // header block fragment. 118 type HeadersFrame struct { 119 http2.FrameHeader 120 121 // Priority is set if FlagHeadersPriority is set in the FrameHeader. 122 Priority http2.PriorityParam 123 124 headerFragBuf []byte // not owned 125 } 126 127 func (f *HeadersFrame) HeaderBlockFragment() []byte { 128 return f.headerFragBuf 129 } 130 131 func (f *HeadersFrame) HeadersEnded() bool { 132 return f.FrameHeader.Flags.Has(http2.FlagHeadersEndHeaders) 133 } 134 135 func (f *HeadersFrame) StreamEnded() bool { 136 return f.FrameHeader.Flags.Has(http2.FlagHeadersEndStream) 137 } 138 139 func (f *HeadersFrame) HasPriority() bool { 140 return f.FrameHeader.Flags.Has(http2.FlagHeadersPriority) 141 } 142 143 func parseHeadersFrame(_ *frameCache, fh http2.FrameHeader, p []byte) (_ http2.Frame, err error) { 144 hf := &HeadersFrame{ 145 FrameHeader: fh, 146 } 147 if fh.StreamID == 0 { 148 // HEADERS frames MUST be associated with a stream. If a HEADERS frame 149 // is received whose stream identifier field is 0x0, the recipient MUST 150 // respond with a connection error (Section 5.4.1) of type 151 // PROTOCOL_ERROR. 152 return nil, connError{http2.ErrCodeProtocol, "HEADERS frame with stream ID 0"} 153 } 154 var padLength uint8 155 if fh.Flags.Has(http2.FlagHeadersPadded) { 156 if p, padLength, err = readByte(p); err != nil { 157 return 158 } 159 } 160 if fh.Flags.Has(http2.FlagHeadersPriority) { 161 var v uint32 162 p, v, err = readUint32(p) 163 if err != nil { 164 return nil, err 165 } 166 hf.Priority.StreamDep = v & 0x7fffffff 167 hf.Priority.Exclusive = (v != hf.Priority.StreamDep) // high bit was set 168 p, hf.Priority.Weight, err = readByte(p) 169 if err != nil { 170 return nil, err 171 } 172 } 173 if len(p)-int(padLength) <= 0 { 174 return nil, http2.StreamError{StreamID: fh.StreamID, Code: http2.ErrCodeProtocol} 175 } 176 hf.headerFragBuf = p[:len(p)-int(padLength)] 177 return hf, nil 178 } 179 180 func parsePriorityFrame(_ *frameCache, fh http2.FrameHeader, payload []byte) (http2.Frame, error) { 181 if fh.StreamID == 0 { 182 return nil, connError{http2.ErrCodeProtocol, "PRIORITY frame with stream ID 0"} 183 } 184 if len(payload) != 5 { 185 return nil, connError{http2.ErrCodeFrameSize, fmt.Sprintf("PRIORITY frame payload size was %d; want 5", len(payload))} 186 } 187 v := binary.BigEndian.Uint32(payload[:4]) 188 streamID := v & 0x7fffffff // mask off high bit 189 return &http2.PriorityFrame{ 190 FrameHeader: fh, 191 PriorityParam: http2.PriorityParam{ 192 Weight: payload[4], 193 StreamDep: streamID, 194 Exclusive: streamID != v, // was high bit set? 195 }, 196 }, nil 197 } 198 199 func parseRSTStreamFrame(_ *frameCache, fh http2.FrameHeader, p []byte) (http2.Frame, error) { 200 if len(p) != 4 { 201 return nil, http2.ConnectionError(http2.ErrCodeFrameSize) 202 } 203 if fh.StreamID == 0 { 204 return nil, http2.ConnectionError(http2.ErrCodeProtocol) 205 } 206 return &http2.RSTStreamFrame{FrameHeader: fh, ErrCode: http2.ErrCode(binary.BigEndian.Uint32(p[:4]))}, nil 207 } 208 209 // A SettingsFrame conveys configuration parameters that affect how 210 // endpoints communicate, such as preferences and constraints on peer 211 // behavior. 212 // 213 // See http://http2.github.io/http2-spec/#SETTINGS 214 type SettingsFrame struct { 215 http2.FrameHeader 216 p []byte 217 } 218 219 func parseSettingsFrame(_ *frameCache, fh http2.FrameHeader, p []byte) (http2.Frame, error) { 220 if fh.Flags.Has(http2.FlagSettingsAck) && fh.Length > 0 { 221 // When this (ACK 0x1) bit is set, the payload of the 222 // SETTINGS frame MUST be empty. Receipt of a 223 // SETTINGS frame with the ACK flag set and a length 224 // field value other than 0 MUST be treated as a 225 // connection error (Section 5.4.1) of type 226 // FRAME_SIZE_ERROR. 227 return nil, http2.ConnectionError(http2.ErrCodeFrameSize) 228 } 229 if fh.StreamID != 0 { 230 // SETTINGS frames always apply to a connection, 231 // never a single stream. The stream identifier for a 232 // SETTINGS frame MUST be zero (0x0). If an endpoint 233 // receives a SETTINGS frame whose stream identifier 234 // field is anything other than 0x0, the endpoint MUST 235 // respond with a connection error (Section 5.4.1) of 236 // type PROTOCOL_ERROR. 237 return nil, http2.ConnectionError(http2.ErrCodeProtocol) 238 } 239 if len(p)%6 != 0 { 240 // Expecting even number of 6 byte settings. 241 return nil, http2.ConnectionError(http2.ErrCodeFrameSize) 242 } 243 f := &SettingsFrame{FrameHeader: fh, p: p} 244 if v, ok := f.Value(http2.SettingInitialWindowSize); ok && v > (1<<31)-1 { 245 // Values above the maximum flow control window size of 2^31 - 1 MUST 246 // be treated as a connection error (Section 5.4.1) of type 247 // FLOW_CONTROL_ERROR. 248 return nil, http2.ConnectionError(http2.ErrCodeFlowControl) 249 } 250 return f, nil 251 } 252 253 func (f *SettingsFrame) IsAck() bool { 254 return f.FrameHeader.Flags.Has(http2.FlagSettingsAck) 255 } 256 257 func (f *SettingsFrame) Value(id http2.SettingID) (v uint32, ok bool) { 258 for i := 0; i < f.NumSettings(); i++ { 259 if s := f.Setting(i); s.ID == id { 260 return s.Val, true 261 } 262 } 263 return 0, false 264 } 265 266 // Setting returns the setting from the frame at the given 0-based index. 267 // The index must be >= 0 and less than f.NumSettings(). 268 func (f *SettingsFrame) Setting(i int) http2.Setting { 269 buf := f.p 270 return http2.Setting{ 271 ID: http2.SettingID(binary.BigEndian.Uint16(buf[i*6 : i*6+2])), 272 Val: binary.BigEndian.Uint32(buf[i*6+2 : i*6+6]), 273 } 274 } 275 276 func (f *SettingsFrame) NumSettings() int { return len(f.p) / 6 } 277 278 // HasDuplicates reports whether f contains any duplicate setting IDs. 279 func (f *SettingsFrame) HasDuplicates() bool { 280 num := f.NumSettings() 281 if num == 0 { 282 return false 283 } 284 // If it's small enough (the common case), just do the n^2 285 // thing and avoid a map allocation. 286 if num < 10 { 287 for i := 0; i < num; i++ { 288 idi := f.Setting(i).ID 289 for j := i + 1; j < num; j++ { 290 idj := f.Setting(j).ID 291 if idi == idj { 292 return true 293 } 294 } 295 } 296 return false 297 } 298 seen := map[http2.SettingID]bool{} 299 for i := 0; i < num; i++ { 300 id := f.Setting(i).ID 301 if seen[id] { 302 return true 303 } 304 seen[id] = true 305 } 306 return false 307 } 308 309 // ForeachSetting runs fn for each setting. 310 // It stops and returns the first error. 311 func (f *SettingsFrame) ForeachSetting(fn func(http2.Setting) error) error { 312 for i := 0; i < f.NumSettings(); i++ { 313 if err := fn(f.Setting(i)); err != nil { 314 return err 315 } 316 } 317 return nil 318 } 319 320 // A PushPromiseFrame is used to initiate a server stream. 321 // See http://http2.github.io/http2-spec/#rfc.section.6.6 322 323 // A PushPromiseFrame is used to initiate a server stream. 324 // See http://http2.github.io/http2-spec/#rfc.section.6.6 325 type PushPromiseFrame struct { 326 http2.FrameHeader 327 PromiseID uint32 328 headerFragBuf []byte // not owned 329 } 330 331 func (f *PushPromiseFrame) HeaderBlockFragment() []byte { 332 return f.headerFragBuf 333 } 334 335 func (f *PushPromiseFrame) HeadersEnded() bool { 336 return f.FrameHeader.Flags.Has(http2.FlagPushPromiseEndHeaders) 337 } 338 339 func parsePushPromise(_ *frameCache, fh http2.FrameHeader, p []byte) (_ http2.Frame, err error) { 340 pp := &PushPromiseFrame{ 341 FrameHeader: fh, 342 } 343 if pp.StreamID == 0 { 344 // PUSH_PROMISE frames MUST be associated with an existing, 345 // peer-initiated stream. The stream identifier of a 346 // PUSH_PROMISE frame indicates the stream it is associated 347 // with. If the stream identifier field specifies the value 348 // 0x0, a recipient MUST respond with a connection error 349 // (Section 5.4.1) of type PROTOCOL_ERROR. 350 return nil, http2.ConnectionError(http2.ErrCodeProtocol) 351 } 352 // The PUSH_PROMISE frame includes optional padding. 353 // Padding fields and flags are identical to those defined for DATA frames 354 var padLength uint8 355 if fh.Flags.Has(http2.FlagPushPromisePadded) { 356 if p, padLength, err = readByte(p); err != nil { 357 return 358 } 359 } 360 361 p, pp.PromiseID, err = readUint32(p) 362 if err != nil { 363 return 364 } 365 pp.PromiseID = pp.PromiseID & (1<<31 - 1) 366 367 if int(padLength) > len(p) { 368 // like the DATA frame, error out if padding is longer than the body. 369 return nil, http2.ConnectionError(http2.ErrCodeProtocol) 370 } 371 pp.headerFragBuf = p[:len(p)-int(padLength)] 372 return pp, nil 373 } 374 375 func parsePingFrame(_ *frameCache, fh http2.FrameHeader, payload []byte) (http2.Frame, error) { 376 if len(payload) != 8 { 377 return nil, http2.ConnectionError(http2.ErrCodeFrameSize) 378 } 379 if fh.StreamID != 0 { 380 return nil, http2.ConnectionError(http2.ErrCodeProtocol) 381 } 382 f := &http2.PingFrame{FrameHeader: fh} 383 copy(f.Data[:], payload) 384 return f, nil 385 } 386 387 // A GoAwayFrame informs the remote peer to stop creating streams on this connection. 388 // See http://http2.github.io/http2-spec/#rfc.section.6.8 389 type GoAwayFrame struct { 390 http2.FrameHeader 391 LastStreamID uint32 392 ErrCode http2.ErrCode 393 debugData []byte 394 } 395 396 // DebugData returns any debug data in the GOAWAY frame. Its contents 397 // are not defined. 398 // The caller must not retain the returned memory past the next 399 // call to ReadFrame. 400 func (f *GoAwayFrame) DebugData() []byte { 401 return f.debugData 402 } 403 404 func parseGoAwayFrame(_ *frameCache, fh http2.FrameHeader, p []byte) (http2.Frame, error) { 405 if fh.StreamID != 0 { 406 return nil, http2.ConnectionError(http2.ErrCodeProtocol) 407 } 408 if len(p) < 8 { 409 return nil, http2.ConnectionError(http2.ErrCodeFrameSize) 410 } 411 return &GoAwayFrame{ 412 FrameHeader: fh, 413 LastStreamID: binary.BigEndian.Uint32(p[:4]) & (1<<31 - 1), 414 ErrCode: http2.ErrCode(binary.BigEndian.Uint32(p[4:8])), 415 debugData: p[8:], 416 }, nil 417 } 418 419 func parseWindowUpdateFrame(_ *frameCache, fh http2.FrameHeader, p []byte) (http2.Frame, error) { 420 if len(p) != 4 { 421 return nil, http2.ConnectionError(http2.ErrCodeFrameSize) 422 } 423 inc := binary.BigEndian.Uint32(p[:4]) & 0x7fffffff // mask off high reserved bit 424 if inc == 0 { 425 // A receiver MUST treat the receipt of a 426 // WINDOW_UPDATE frame with an flow control window 427 // increment of 0 as a stream error (Section 5.4.2) of 428 // type PROTOCOL_ERROR; errors on the connection flow 429 // control window MUST be treated as a connection 430 // error (Section 5.4.1). 431 if fh.StreamID == 0 { 432 return nil, http2.ConnectionError(http2.ErrCodeProtocol) 433 } 434 return nil, http2.StreamError{StreamID: fh.StreamID, Code: http2.ErrCodeProtocol} 435 } 436 return &http2.WindowUpdateFrame{ 437 FrameHeader: fh, 438 Increment: inc, 439 }, nil 440 } 441 442 // A ContinuationFrame is used to continue a sequence of header block fragments. 443 // See http://http2.github.io/http2-spec/#rfc.section.6.10 444 type ContinuationFrame struct { 445 http2.FrameHeader 446 headerFragBuf []byte 447 } 448 449 func parseContinuationFrame(_ *frameCache, fh http2.FrameHeader, p []byte) (http2.Frame, error) { 450 if fh.StreamID == 0 { 451 return nil, connError{http2.ErrCodeProtocol, "CONTINUATION frame with stream ID 0"} 452 } 453 return &ContinuationFrame{FrameHeader: fh, headerFragBuf: p}, nil 454 } 455 456 func (f *ContinuationFrame) HeaderBlockFragment() []byte { 457 return f.headerFragBuf 458 } 459 460 func (f *ContinuationFrame) HeadersEnded() bool { 461 return f.FrameHeader.Flags.Has(http2.FlagContinuationEndHeaders) 462 } 463 464 // An UnknownFrame is the frame type returned when the frame type is unknown 465 // or no specific frame type parser exists. 466 type UnknownFrame struct { 467 http2.FrameHeader 468 p []byte 469 } 470 471 // Payload returns the frame's payload (after the header). It is not 472 // valid to call this method after a subsequent call to 473 // Framer.ReadFrame, nor is it valid to retain the returned slice. 474 // The memory is owned by the Framer and is invalidated when the next 475 // frame is read. 476 func (f *UnknownFrame) Payload() []byte { 477 return f.p 478 } 479 480 func parseUnknownFrame(_ *frameCache, fh http2.FrameHeader, p []byte) (http2.Frame, error) { 481 return &UnknownFrame{fh, p}, nil 482 } 483 484 // A MetaHeadersFrame is the representation of one HEADERS frame and 485 // zero or more contiguous CONTINUATION frames and the decoding of 486 // their HPACK-encoded contents. 487 // 488 // This type of frame does not appear on the wire and is only returned 489 // by the Framer when Framer.ReadMetaHeaders is set. 490 type MetaHeadersFrame struct { 491 *HeadersFrame 492 493 // Fields are the fields contained in the HEADERS and 494 // CONTINUATION frames. The underlying slice is owned by the 495 // Framer and must not be retained after the next call to 496 // ReadFrame. 497 // 498 // Fields are guaranteed to be in the correct http2 order and 499 // not have unknown pseudo header fields or invalid header 500 // field names or values. Required pseudo header fields may be 501 // missing, however. Use the MetaHeadersFrame.Pseudo accessor 502 // method access pseudo headers. 503 Fields []hpack.HeaderField 504 505 // Truncated is whether the max header list size limit was hit 506 // and Fields is incomplete. The hpack decoder state is still 507 // valid, however. 508 Truncated bool 509 } 510 511 // PseudoValue returns the given pseudo header field's value. 512 // The provided pseudo field should not contain the leading colon. 513 func (mh *MetaHeadersFrame) PseudoValue(pseudo string) string { 514 for _, hf := range mh.Fields { 515 if !hf.IsPseudo() { 516 return "" 517 } 518 if hf.Name[1:] == pseudo { 519 return hf.Value 520 } 521 } 522 return "" 523 } 524 525 // RegularFields returns the regular (non-pseudo) header fields of mh. 526 // The caller does not own the returned slice. 527 func (mh *MetaHeadersFrame) RegularFields() []hpack.HeaderField { 528 for i, hf := range mh.Fields { 529 if !hf.IsPseudo() { 530 return mh.Fields[i:] 531 } 532 } 533 return nil 534 } 535 536 // PseudoFields returns the pseudo header fields of mh. 537 // The caller does not own the returned slice. 538 func (mh *MetaHeadersFrame) PseudoFields() []hpack.HeaderField { 539 for i, hf := range mh.Fields { 540 if !hf.IsPseudo() { 541 return mh.Fields[:i] 542 } 543 } 544 return mh.Fields 545 } 546 547 func (mh *MetaHeadersFrame) checkPseudos() error { 548 var isRequest, isResponse bool 549 pf := mh.PseudoFields() 550 for i, hf := range pf { 551 switch hf.Name { 552 case ":method", ":path", ":scheme", ":authority": 553 isRequest = true 554 case ":status": 555 isResponse = true 556 default: 557 return pseudoHeaderError(hf.Name) 558 } 559 // Check for duplicates. 560 // This would be a bad algorithm, but N is 4. 561 // And this doesn't allocate. 562 for _, hf2 := range pf[:i] { 563 if hf.Name == hf2.Name { 564 return duplicatePseudoHeaderError(hf.Name) 565 } 566 } 567 } 568 if isRequest && isResponse { 569 return errMixPseudoHeaderTypes 570 } 571 return nil 572 }